diff --git a/CHANGELOG.md b/CHANGELOG.md index 00eac8d..4c7161f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ Alle wesentlichen Aenderungen an Enelix EMS werden in dieser Datei dokumentiert. ### Beta-Aenderungen +- Ladestationen halten beim Aktivieren und Umschalten von Solarladen den bisherigen Strom bis zur neuen Manager-Vorgabe; die Stand-alone-Phasenprobe verwendet nur noch 6 A. +- Fahrzeugstatus ist bei beiden Ladestationsvarianten eine Diagnosevariable, Ist- und Sollleistung gehoeren zu den optionalen Visualisierungseinstellungen. - Stufenlose Leistungsbereiche fuer Batteriespeicher. - Ladefreigabe neuer Ladestationsinstanzen standardmaessig aktiviert. - Stand-alone-Ladestationen erkennen nach einer einstellbaren Beobachtungszeit den niedrigeren Fahrzeug-Maximalstrom und begrenzen ihr Leistungsangebot ohne Ladeunterbruch. diff --git a/LadestationGateway/module.php b/LadestationGateway/module.php index 383b3f3..e10942f 100644 --- a/LadestationGateway/module.php +++ b/LadestationGateway/module.php @@ -28,17 +28,17 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle private const STATUS_GATEWAY_GETRENNT = 202; private const STATUS_WARTET_AUF_DATEN = 203; private const STATUS_LADEFEHLER = 204; + private const REGELUEBERGANG_TIMEOUT_MS = 2000; /** @var list */ private const DIAGNOSE_VARIABLEN = [ - 'Istleistung', 'Leistungsquelle', - 'Sollleistung', 'SollwertGueltig', 'Verfuegbar', 'AenderungMoeglich', 'Stoerung', 'Stoertext', + 'Fahrzeugstatus', 'GatewayVerbunden', 'ApiMaximalstrom', 'EaseeAktiviert', @@ -75,7 +75,6 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle '~Switch', 110 ); - $this->RegisterVariableInteger('Fahrzeugstatus', 'Fahrzeugstatus', '', 120); $this->RegisterVariableFloat('Ladestrom', 'Ladestrom', '', 130); $this->RegisterVariableInteger('Phasenzahl', 'Phasenzahl', '', 140); @@ -113,6 +112,7 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle $this->RegisterAttributeBoolean('LadestartFuerVerbindungGesendet', false); $this->RegisterAttributeString('LetzterGeraetebefehl', ''); $this->RegisterAttributeString('LetzterStartbefehl', ''); + $this->RegisterAttributeBoolean('RegeluebergangAktiv', false); $this->RegisterTimer( 'Meldezyklus', @@ -129,6 +129,11 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle 0, "IPS_RequestAction(\$_IPS['TARGET'], 'VorgabeTimeout', false);" ); + $this->RegisterTimer( + 'RegeluebergangTimeout', + 0, + "IPS_RequestAction(\$_IPS['TARGET'], 'RegeluebergangTimeout', false);" + ); $this->ConnectParent(self::EASEE_GATEWAY_MODULE_ID); } @@ -142,6 +147,7 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle $this->WriteAttributeBoolean('GatewayVerbunden', false); $this->WriteAttributeInteger('LetzterGesetzterStrom', -1); $this->WriteAttributeBoolean('LadestartFuerVerbindungGesendet', false); + $this->beendeRegeluebergang(); try { $this->pruefeKonfiguration(); @@ -167,17 +173,27 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle { switch ($ident) { case 'Aktiv': - $this->SetValue('Aktiv', (bool) $wert); - if (!(bool) $wert) { + $aktiv = (bool) $wert; + $this->SetValue('Aktiv', $aktiv); + if ($aktiv) { + $this->starteRegeluebergang(); + } else { + $this->beendeRegeluebergang(); $this->setzeZustand('SollwertGueltig', false); } $this->aktualisiere(true); return; case 'Ladefreigabe': - $this->WriteAttributeBoolean('ZustandLadefreigabe', (bool) $wert); - $this->setzeSichtbareVariable('Ladefreigabe', (bool) $wert); - $this->setzeZustand('SollwertGueltig', false); + $ladefreigabe = (bool) $wert; + $this->WriteAttributeBoolean('ZustandLadefreigabe', $ladefreigabe); + $this->setzeSichtbareVariable('Ladefreigabe', $ladefreigabe); + if ($ladefreigabe) { + $this->starteRegeluebergang(); + } else { + $this->beendeRegeluebergang(); + $this->setzeZustand('SollwertGueltig', false); + } $this->aktualisiere(true); return; @@ -185,9 +201,11 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle $solarladen = EaseeLadestatus::solarladenErzwungen( $this->ReadPropertyInteger('Betriebsmodus') ) ? true : (bool) $wert; + if ($solarladen !== $this->ReadAttributeBoolean('ZustandSolarladen')) { + $this->starteRegeluebergang(); + } $this->WriteAttributeBoolean('ZustandSolarladen', $solarladen); $this->setzeSichtbareVariable('Solarladen', $solarladen); - $this->setzeZustand('SollwertGueltig', false); $this->aktualisiere(true); return; @@ -201,6 +219,11 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle $this->aktualisiere(true); return; + case 'RegeluebergangTimeout': + $this->beendeRegeluebergang(); + $this->aktualisiere(true); + return; + case 'Melden': if ((bool) $wert) { $this->SetTimerInterval('RueckmeldungVerzoegert', 0); @@ -288,7 +311,7 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle } $this->WriteAttributeString('Betriebsart', $daten['Betriebsart']); - $this->aktualisiere(false); + $this->aktualisiere(false, false); $sollleistung = $daten['Sollleistung_W']; if ($sollleistung === null) { if ( @@ -311,6 +334,7 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle ); } + $this->beendeRegeluebergang(); $this->WriteAttributeInteger('LetzteManagerID', $managerID); $this->WriteAttributeInteger('LetzteVorgabeZeit', time()); $this->setzeZustand('Sollleistung', $sollleistung); @@ -405,7 +429,10 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle $this->WriteAttributeInteger('LetzteBeobachtung', $zeitpunkt); } - private function aktualisiere(bool $meldungPlanen): void + private function aktualisiere( + bool $meldungPlanen, + bool $steuerungAusfuehren = true + ): void { try { $status = EaseeLadestatus::ausBeobachtungen( @@ -493,12 +520,21 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle } $this->setzeStoerung($stoertext); + $regeluebergangAktiv = (bool) $this->GetValue('Aktiv') + && $this->ReadAttributeBoolean('ZustandLadefreigabe') + && $steuerbar + && $status['FahrzeugVerbunden'] + && !$status['FahrzeugGeladen'] + && $this->ReadAttributeBoolean('RegeluebergangAktiv'); if ($gatewayVerbunden && $status['StatusGueltig']) { - $this->setzeLadestrom( - $this->bestimmeWirksameSollleistung($angebot), - $regelPhasenzahl, - $status['Fahrzeugstatus'] === 2 - ); + $sollleistung = $this->bestimmeWirksameSollleistung($angebot); + if ($steuerungAusfuehren && !$regeluebergangAktiv) { + $this->setzeLadestrom( + $sollleistung, + $regelPhasenzahl, + $status['Fahrzeugstatus'] === 2 + ); + } } else { $this->WriteAttributeInteger('LetzterGesetzterStrom', -1); } @@ -797,6 +833,23 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle return is_array($zuordnung) ? $zuordnung : []; } + private function starteRegeluebergang(): void + { + if ($this->zugeordneteManagerIDs() === []) { + $this->beendeRegeluebergang(); + return; + } + + $this->WriteAttributeBoolean('RegeluebergangAktiv', true); + $this->SetTimerInterval('RegeluebergangTimeout', self::REGELUEBERGANG_TIMEOUT_MS); + } + + private function beendeRegeluebergang(): void + { + $this->WriteAttributeBoolean('RegeluebergangAktiv', false); + $this->SetTimerInterval('RegeluebergangTimeout', 0); + } + private function pruefeKonfiguration(): void { foreach (['PrioritaetPV', 'PrioritaetPeak'] as $property) { @@ -857,95 +910,63 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle 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->RegisterVariableInteger('Fahrzeugstatus', 'Fahrzeugstatus', '', 200); $this->RegisterVariableBoolean( 'GatewayVerbunden', 'Easee Gateway verbunden', '~Switch', - 200 - ); - $this->RegisterVariableInteger( - 'ApiMaximalstrom', - 'API-Maximalstrom', - '', 210 ); + $this->RegisterVariableInteger('ApiMaximalstrom', 'API-Maximalstrom', '', 220); $this->RegisterVariableBoolean( 'EaseeAktiviert', 'Easee aktiviert', '~Switch', - 220 + 230 ); $this->RegisterVariableBoolean( 'AutorisierungErforderlich', 'Autorisierung erforderlich', '~Switch', - 230 + 240 ); $this->RegisterVariableBoolean( 'RemoteStartErforderlich', 'Remote-Start erforderlich', '~Switch', - 240 + 250 ); $this->RegisterVariableBoolean( 'SmartCharging', 'Easee Smart Charging', '~Switch', - 250 + 260 ); $this->RegisterVariableInteger( 'GrundKeinLadestrom', 'Grund kein Ladestrom', '', - 260 + 270 ); $this->RegisterVariableString( 'LetzterGeraetebefehl', 'Letzter Geraetebefehl', '', - 270 + 280 ); $this->RegisterVariableString( 'LetzterStartbefehl', 'Letzter Startbefehl', '', - 280 + 290 ); $this->RegisterVariableString( 'LeistungsangebotDiagnose', 'Leistungsangebot', '', - 290 + 300 ); $this->SetValue( 'LeistungsangebotDiagnose', @@ -983,6 +1004,40 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle $this->entferneVariable($ident); } } + + if ($this->ReadPropertyBoolean('EinstellungenInVisu')) { + $this->RegisterVariableBoolean( + 'Ladefreigabe', + 'Ladefreigabe', + '~Switch', + 150 + ); + $this->RegisterVariableBoolean( + 'Solarladen', + 'Solarladen', + '~Switch', + 160 + ); + $this->RegisterVariableFloat('Istleistung', 'Istleistung', '', 170); + $this->RegisterVariableInteger('Sollleistung', 'Sollleistung', '', 180); + $this->EnableAction('Ladefreigabe'); + $this->EnableAction('Solarladen'); + $this->SetValue( + 'Ladefreigabe', + $this->ReadAttributeBoolean('ZustandLadefreigabe') + ); + $this->SetValue( + 'Solarladen', + $this->ReadAttributeBoolean('ZustandSolarladen') + ); + $this->SetValue('Istleistung', $this->ReadAttributeFloat('ZustandIstleistung')); + $this->SetValue('Sollleistung', $this->ReadAttributeInteger('ZustandSollleistung')); + } else { + $this->entferneVariable('Ladefreigabe'); + $this->entferneVariable('Solarladen'); + $this->entferneVariable('Istleistung'); + $this->entferneVariable('Sollleistung'); + } } private function entferneVariable(string $ident): void @@ -1108,7 +1163,12 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle private function deaktiviereTimer(): void { - foreach (['Meldezyklus', 'RueckmeldungVerzoegert', 'VorgabeTimeout'] as $timer) { + foreach ([ + 'Meldezyklus', + 'RueckmeldungVerzoegert', + 'VorgabeTimeout', + 'RegeluebergangTimeout', + ] as $timer) { $this->SetTimerInterval($timer, 0); } } diff --git a/LadestationStandAlone/module.php b/LadestationStandAlone/module.php index 4097517..6258dcd 100644 --- a/LadestationStandAlone/module.php +++ b/LadestationStandAlone/module.php @@ -23,17 +23,18 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell private const STATUS_AKTIV = 102; private const STATUS_KONFIGURATION_UNGUELTIG = 201; private const STATUS_KOMMUNIKATIONSFEHLER = 202; + private const REGELUEBERGANG_TIMEOUT_MS = 2000; + private const PHASENERKENNUNGSSTROM = 6; /** @var list */ private const DIAGNOSE_VARIABLEN = [ - 'Istleistung', 'Leistungsquelle', - 'Sollleistung', 'SollwertGueltig', 'Verfuegbar', 'AenderungMoeglich', 'Stoerung', 'Stoertext', + 'Fahrzeugstatus', 'FahrzeugMaximalstrom', 'LetzterGeraetebefehl', 'LeistungsangebotDiagnose', @@ -67,7 +68,6 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell $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); @@ -103,6 +103,7 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell $this->RegisterAttributeInteger('ErkannterMaximalstrom', 32); $this->RegisterAttributeInteger('FahrzeugstromKandidat', 0); $this->RegisterAttributeInteger('FahrzeugstromKandidatSeit', 0); + $this->RegisterAttributeBoolean('RegeluebergangAktiv', false); $this->RegisterTimer( 'Statuszyklus', @@ -124,6 +125,11 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell 0, "IPS_RequestAction(\$_IPS['TARGET'], 'VorgabeTimeout', false);" ); + $this->RegisterTimer( + 'RegeluebergangTimeout', + 0, + "IPS_RequestAction(\$_IPS['TARGET'], 'RegeluebergangTimeout', false);" + ); } public function ApplyChanges(): void @@ -154,6 +160,7 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell $this->ReadPropertyInteger('MaximalerLadestrom') ); $this->setzeFahrzeugstromKandidatZurueck(); + $this->beendeRegeluebergang(); try { $this->pruefeKonfiguration(); @@ -176,18 +183,37 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell { switch ($ident) { case 'Aktiv': - $this->SetValue('Aktiv', (bool) $wert); - if (!(bool) $wert) { + $aktiv = (bool) $wert; + $this->SetValue('Aktiv', $aktiv); + if ($aktiv) { + $this->starteRegeluebergang(); + } else { + $this->beendeRegeluebergang(); $this->setzeZustand('SollwertGueltig', false); } $this->aktualisiere(true); return; case 'Ladefreigabe': + $ladefreigabe = (bool) $wert; + $this->WriteAttributeBoolean('ZustandLadefreigabe', $ladefreigabe); + $this->setzeSichtbareVariable('Ladefreigabe', $ladefreigabe); + if ($ladefreigabe) { + $this->starteRegeluebergang(); + } else { + $this->beendeRegeluebergang(); + $this->setzeZustand('SollwertGueltig', false); + } + $this->aktualisiere(true); + return; + case 'Solarladen': - $this->WriteAttributeBoolean('Zustand' . $ident, (bool) $wert); - $this->setzeSichtbareVariable($ident, (bool) $wert); - $this->setzeZustand('SollwertGueltig', false); + $solarladen = (bool) $wert; + if ($solarladen !== $this->ReadAttributeBoolean('ZustandSolarladen')) { + $this->starteRegeluebergang(); + } + $this->WriteAttributeBoolean('ZustandSolarladen', $solarladen); + $this->setzeSichtbareVariable('Solarladen', $solarladen); $this->aktualisiere(true); return; @@ -201,6 +227,11 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell $this->aktualisiere(true); return; + case 'RegeluebergangTimeout': + $this->beendeRegeluebergang(); + $this->aktualisiere(true); + return; + case 'Melden': if ((bool) $wert) { $this->SetTimerInterval('RueckmeldungVerzoegert', 0); @@ -238,7 +269,7 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell } $this->WriteAttributeString('Betriebsart', $daten['Betriebsart']); - $this->aktualisiere(false, false); + $this->aktualisiere(false, false, false); $sollleistung = $daten['Sollleistung_W']; if ($sollleistung === null) { if ((bool) $this->leseZustand('SollwertGueltig') @@ -256,6 +287,7 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell ); } + $this->beendeRegeluebergang(); $this->WriteAttributeInteger('LetzteManagerID', $managerID); $this->WriteAttributeInteger('LetzteVorgabeZeit', time()); $this->setzeZustand('Sollleistung', $sollleistung); @@ -265,7 +297,11 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell $this->SetTimerInterval('RueckmeldungVerzoegert', 100); } - private function aktualisiere(bool $meldungPlanen, bool $statusLesen = true): void + private function aktualisiere( + bool $meldungPlanen, + bool $statusLesen = true, + bool $steuerungAusfuehren = true + ): void { try { if ($statusLesen) { @@ -346,12 +382,17 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell $this->setzeZustand('AenderungMoeglich', $verfuegbar && count($angebot) > 1); $sollleistung = $this->bestimmeWirksameSollleistung($angebot); - if (!($aktiv + $phasenerkennungAktiv = $aktiv && $ladefreigabe && $verbunden && !$geladen - && $phasenzahl === LadestationRegler::PHASEN_UNBEKANNT - )) { + && $phasenzahl === LadestationRegler::PHASEN_UNBEKANNT; + $regeluebergangAktiv = $aktiv + && $ladefreigabe + && $verbunden + && !$geladen + && $this->ReadAttributeBoolean('RegeluebergangAktiv'); + if ($steuerungAusfuehren && !$phasenerkennungAktiv && !$regeluebergangAktiv) { $this->setzeLadestrom($sollleistung); } $this->setzeStoerung(''); @@ -413,17 +454,16 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell ) { $erkennungSeit = $this->ReadAttributeInteger('PhasenerkennungSeit'); if ($erkennungSeit <= 0) { - $this->sendeLadestromAnGeraet( - $this->ReadPropertyInteger('MaximalerLadestrom') - ); + $this->sendeLadestromAnGeraet(self::PHASENERKENNUNGSSTROM); $erkennungSeit = time(); $this->WriteAttributeInteger('PhasenerkennungSeit', $erkennungSeit); } elseif ((time() - $erkennungSeit) >= $this->ReadPropertyInteger('Phasenerkennungszeit') ) { - $bekanntePhasenzahl = $rohstatus['Istleistung_W'] > 7500.0 - ? LadestationRegler::PHASEN_DREI - : LadestationRegler::PHASEN_EIN; + $bekanntePhasenzahl = LadestationRegler::erkennePhasenzahlAusLeistung( + (float) $rohstatus['Istleistung_W'], + $this->ReadAttributeInteger('LetzterGesetzterStrom') + ); $this->WriteAttributeInteger('PhasenerkennungSeit', 0); } } else { @@ -819,6 +859,23 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell return is_array($zuordnung) ? $zuordnung : []; } + private function starteRegeluebergang(): void + { + if ($this->zugeordneteManagerIDs() === []) { + $this->beendeRegeluebergang(); + return; + } + + $this->WriteAttributeBoolean('RegeluebergangAktiv', true); + $this->SetTimerInterval('RegeluebergangTimeout', self::REGELUEBERGANG_TIMEOUT_MS); + } + + private function beendeRegeluebergang(): void + { + $this->WriteAttributeBoolean('RegeluebergangAktiv', false); + $this->SetTimerInterval('RegeluebergangTimeout', 0); + } + private function pruefeKonfiguration(): void { foreach (['PrioritaetPV', 'PrioritaetPeak'] as $property) { @@ -882,27 +939,16 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell 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->RegisterVariableInteger('Fahrzeugstatus', 'Fahrzeugstatus', '', 200); + $this->RegisterVariableString('LetzterGeraetebefehl', 'Letzter Geraetebefehl', '', 210); + $this->RegisterVariableString('LeistungsangebotDiagnose', 'Leistungsangebot', '', 220); $this->RegisterVariableInteger( 'FahrzeugMaximalstrom', 'Erkannter Fahrzeug-Maximalstrom', '', - 220 + 230 ); $this->SetValue( 'FahrzeugMaximalstrom', @@ -926,6 +972,24 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell $this->entferneVariable($ident); } } + + if ($this->ReadPropertyBoolean('EinstellungenInVisu')) { + $this->RegisterVariableBoolean('Ladefreigabe', 'Ladefreigabe', '~Switch', 150); + $this->RegisterVariableBoolean('Solarladen', 'Solarladen', '~Switch', 160); + $this->RegisterVariableFloat('Istleistung', 'Istleistung', '', 170); + $this->RegisterVariableInteger('Sollleistung', 'Sollleistung', '', 180); + $this->EnableAction('Ladefreigabe'); + $this->EnableAction('Solarladen'); + $this->SetValue('Ladefreigabe', $this->ReadAttributeBoolean('ZustandLadefreigabe')); + $this->SetValue('Solarladen', $this->ReadAttributeBoolean('ZustandSolarladen')); + $this->SetValue('Istleistung', $this->ReadAttributeFloat('ZustandIstleistung')); + $this->SetValue('Sollleistung', $this->ReadAttributeInteger('ZustandSollleistung')); + } else { + $this->entferneVariable('Ladefreigabe'); + $this->entferneVariable('Solarladen'); + $this->entferneVariable('Istleistung'); + $this->entferneVariable('Sollleistung'); + } } private function entferneVariable(string $ident): void @@ -1033,7 +1097,13 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell private function deaktiviereTimer(): void { - foreach (['Statuszyklus', 'Meldezyklus', 'RueckmeldungVerzoegert', 'VorgabeTimeout'] as $timer) { + foreach ([ + 'Statuszyklus', + 'Meldezyklus', + 'RueckmeldungVerzoegert', + 'VorgabeTimeout', + 'RegeluebergangTimeout', + ] as $timer) { $this->SetTimerInterval($timer, 0); } } diff --git a/docs/module/Ladestation-Gateway/README.md b/docs/module/Ladestation-Gateway/README.md index cb29912..3093af8 100644 --- a/docs/module/Ladestation-Gateway/README.md +++ b/docs/module/Ladestation-Gateway/README.md @@ -50,22 +50,22 @@ als ungueltig behandelt und ergeben bis zur gueltigen 1-/3-Phasenmeldung nur | `PrioritaetPeak` | Integer | `0` | Prioritaet im Peakbetrieb. | | `Meldeintervall` | Integer | `10 s` | Periodische Vollmeldung an den Manager. | | `VorgabeTimeout` | Integer | `120 s` | Ablauf einer nicht erneuerten Manager-Vorgabe. | -| `EinstellungenInVisu` | Boolean | `false` | Zeigt Ladefreigabe und Solarladen. | +| `EinstellungenInVisu` | Boolean | `false` | Zeigt Ladefreigabe, Solarladen, Istleistung und Sollleistung. | | `DiagnosevariablenAnzeigen` | Boolean | `false` | Zeigt technische Diagnosewerte. | | `LoggingEin` | Boolean | `false` | Aktiviert Debugmeldungen ohne Geheimnisse. | ## Variablen Immer sichtbar sind `Aktiv`, `FahrzeugVerbunden`, `FahrzeugGeladen`, -`Fahrzeugstatus`, `Ladestrom` und `Phasenzahl`. Der normalisierte -Fahrzeugstatus ist `0` unbekannt, `1` getrennt, `2` wartet auf Start, -`3` laedt, `4` geladen oder `5` Fehler. +`Ladestrom` und `Phasenzahl`. Mit `EinstellungenInVisu=true` erscheinen +zusaetzlich `Ladefreigabe`, `Solarladen`, `Istleistung` und `Sollleistung`. -Optional sichtbar sind die gemeinsamen EMS-Diagnosewerte sowie +Mit `DiagnosevariablenAnzeigen=true` werden der numerische `Fahrzeugstatus` +und die gemeinsamen EMS-Diagnosewerte sowie `GatewayVerbunden`, `ApiMaximalstrom`, `EaseeAktiviert`, `AutorisierungErforderlich`, `RemoteStartErforderlich`, `SmartCharging`, `GrundKeinLadestrom`, `LetzterGeraetebefehl`, `LetzterStartbefehl` und -`LeistungsangebotDiagnose`. `GrundKeinLadestrom=55` bedeutet bei Easee, dass +`LeistungsangebotDiagnose` angezeigt. `GrundKeinLadestrom=55` bedeutet bei Easee, dass die Autorisierung fehlt. ## Regelung @@ -83,6 +83,11 @@ Ladestation Stand-Alone: Die niedrigste Grenze aus Property, Observation `47` und Observation `104` bestimmt den angebotenen Maximalstrom. Eine neue Observation berechnet das Angebot sofort neu und meldet die Aenderung kurz gebuendelt an den Manager. +Beim Aktivieren oder Umschalten von Solarladen bleibt der bisherige +Geraetestrom bis zur neuen Manager-Vorgabe unveraendert. Ohne Managerantwort +greift nach zwei Sekunden das lokale Ersatzverhalten. Sicherheitsabschaltungen +werden nicht verzoegert. + Bei einer Gateway-Unterbrechung werden Fahrzeug- und Phasenstatus sofort verworfen; erst ein neuer aktueller Gateway-Zustand gibt die Regelung wieder frei. Die eigentliche Vorgabe wird als dynamischer Ladestrom mit `minutes=0` diff --git a/docs/module/Ladestation-Stand-Alone/README.md b/docs/module/Ladestation-Stand-Alone/README.md index d387fef..7af4b03 100644 --- a/docs/module/Ladestation-Stand-Alone/README.md +++ b/docs/module/Ladestation-Stand-Alone/README.md @@ -43,11 +43,11 @@ Die Auswertung folgt bewusst dem Verhalten der bisherigen Enelix-1-Ladestation: 3. go-e meldet die drei Phasenstroeme einzeln. Sobald mindestens zwei Phasen Strom fuehren, wird dreiphasiges Laden direkt erkannt. 4. Sind beim Anstecken noch keine belastbaren Phasenwerte vorhanden, gibt das - Modul zunaechst den konfigurierten Maximalstrom als Erkennungsstrom vor. Bis - zur abgeschlossenen Erkennung bleibt `Phasenzahl=0` und das EMS-Angebot - `[0]`. -5. Nach `Phasenerkennungszeit` gilt wie in Enelix 1: ueber 7500 W werden drei - Phasen erkannt, andernfalls eine Phase. Die erkannte Phasenzahl bleibt bis + Modul zunaechst nur den Mindeststrom von 6 A als Erkennungsstrom vor. Bis zur + abgeschlossenen Erkennung bleibt `Phasenzahl=0` und das EMS-Angebot `[0]`. +5. Nach `Phasenerkennungszeit` wird die gemessene Leistung relativ zum + angeforderten Erkennungsstrom ausgewertet. Dadurch lassen sich eine und drei + Phasen bereits bei 6 A unterscheiden. Die erkannte Phasenzahl bleibt bis zum Ausstecken erhalten und kippt waehrend einer Ladepause nicht zurueck. 6. Der Ladestrom wird aus der Leistung mit `230 W/A` einphasig beziehungsweise `684 W/A` dreiphasig berechnet. @@ -84,6 +84,12 @@ Die Leistungsstufen entsprechen Enelix 1: `230 W` pro Ampere einphasig und bei aktivem Solarladen mit `0 A`; bei ausgeschaltetem Solarladen verwendet es die maximale angebotene Leistung. +Beim Aktivieren oder Umschalten von Solarladen bleibt ein bereits gesetzter +Geraetestrom zunaechst unveraendert. Das neue Angebot wird zuerst an den +zugeordneten Manager gemeldet; dessen neue Vorgabe wird anschliessend direkt +uebernommen. Antwortet kein Manager, greift nach zwei Sekunden das lokale +Ersatzverhalten. Sicherheitsabschaltungen wirken weiterhin sofort. + Nach einer Leistungsaenderung wird die aktuelle Stufe fuer `ZeitZwischenZustandswechseln` gehalten. Waehrend der `Mindesteinschaltdauer` bleiben positive Leistungsstufen regelbar, `0 W` @@ -115,7 +121,7 @@ gueltige Manager-Vorgabe und berechnet das Leistungsangebot sofort neu. | `PrioritaetPeak` | Integer | `0` | Prioritaet des Verbrauchers im Peakbetrieb. | | `Meldeintervall` | Integer | `10 s` | Intervall fuer die periodische Vollmeldung an zugeordnete Manager. | | `VorgabeTimeout` | Integer | `120 s` | Gueltigkeitsdauer einer Manager-Vorgabe ohne Erneuerung. | -| `EinstellungenInVisu` | Boolean | `false` | Blendet `Ladefreigabe` und `Solarladen` als bedienbare Variablen ein. | +| `EinstellungenInVisu` | Boolean | `false` | Blendet `Ladefreigabe`, `Solarladen`, `Istleistung` und `Sollleistung` ein. | | `LoggingEin` | Boolean | `false` | Aktiviert das laufende Debug-Protokoll des Moduls. | ### Ladestation und Diagnose @@ -129,7 +135,7 @@ gueltige Manager-Vorgabe und berechnet das Leistungsangebot sofort neu. | `Benutzername` | String | leer | Benutzername fuer die Pico-API. | | `Passwort` | String | leer | Passwort fuer die Pico-API; im Formular als Passwortfeld dargestellt. | | `MaximalerLadestrom` | Integer | `16 A` | Obergrenze der angebotenen Ladestufen; zulaessig sind 6 bis 32 A. | -| `Phasenerkennungszeit` | Integer | `60 s` | Dauer der Maximalstrom-Probe vor der leistungsbasierten Phasenerkennung. | +| `Phasenerkennungszeit` | Integer | `60 s` | Dauer der 6-A-Probe vor der leistungsbasierten Phasenerkennung. | | `FahrzeugstromErkennungszeit` | Integer | `90 s` | Zeit, die eine stabile Stromunterschreitung anliegen muss, bevor die Fahrzeuggrenze mit 2,5 A Reserve uebernommen wird. | | `ZeitZwischenZustandswechseln` | Integer | `1 min` | Mindestabstand zwischen zwei Leistungsaenderungen. | | `Mindesteinschaltdauer` | Integer | `0 min` | Mindestdauer nach dem Einschalten, in der kein Abschalten auf 0 W angeboten wird. | @@ -152,22 +158,22 @@ Immer sichtbar: | `Aktiv` | Boolean / bedienbar | Lokale EMS-Freigabe; der Initialwert ist `false`. | | `FahrzeugVerbunden` | Boolean / Anzeige | Zeigt, ob die API ein verbundenes Fahrzeug meldet. | | `FahrzeugGeladen` | Boolean / Anzeige | Ergebnis der kompatiblen Enelix-1-Voll-Erkennung. | -| `Fahrzeugstatus` | Integer / Anzeige | Normalisierter Status von `0` bis `4`. | | `Ladestrom` | Float / Anzeige | Aus der gemessenen Leistung ermittelter Ladestrom in A. | | `Phasenzahl` | Integer / Anzeige | `0` unbekannt, `1` einphasig oder `3` dreiphasig. | -Nur mit `EinstellungenInVisu=true` sichtbar und bedienbar: +Nur mit `EinstellungenInVisu=true` sichtbar; Ladefreigabe und Solarladen sind bedienbar: - `Ladefreigabe` - `Solarladen` +- `Istleistung` +- `Sollleistung` Nur mit `DiagnosevariablenAnzeigen=true` sichtbar: | Ident | Beschreibung | | --- | --- | -| `Istleistung` | Von der Ladestation gemessene Leistung in W. | | `Leistungsquelle` | Immer `2` fuer eine gemessene Leistung. | -| `Sollleistung` | Letzte angenommene Manager-Vorgabe in W. | +| `Fahrzeugstatus` | Normalisierter Status von `0` bis `4`. | | `SollwertGueltig` | Zeigt, ob die Vorgabe noch gueltig und im aktuellen Angebot enthalten ist. | | `Verfuegbar` | Zeigt, ob die Ladestation grundsaetzlich Leistung aufnehmen kann. | | `AenderungMoeglich` | Zeigt, ob das aktuelle Angebot mehr als eine Leistungsstufe enthaelt. | @@ -253,8 +259,8 @@ niemals in Repository-Dateien, Skripte oder Screenshots. - Ohne Fahrzeug sind `FahrzeugVerbunden=false`, `Phasenzahl=0` und das Leistungsangebot `[0]`. - Nach dem Anstecken wird das Fahrzeug erkannt und bei unbekannten Phasen - zunaechst der konfigurierte Maximalstrom zur Erkennung angefordert. -- Nach der Erkennungszeit werden bis 7500 W eine Phase, darueber drei Phasen + zunaechst der Mindeststrom von 6 A zur Erkennung angefordert. +- Nach der Erkennungszeit werden eine oder drei Phasen relativ zum Pruefstrom gespeichert. Bei go-e koennen die einzelnen Phasenstroeme die Erkennung bereits vorher abschliessen. - Die erkannte Phasenzahl bleibt bei einer anschliessenden Ladepause stabil. @@ -298,7 +304,7 @@ URL, HTTP-Methode, Authentisierung und Steueraufrufe ohne reale Hardware geprueft. Der Symcon-Funktionstest verwendet den internen `Testmodus` mit simulierten -API-Antworten. Er prueft alle drei Geraetevarianten, die Maximalstrom-Probe +API-Antworten. Er prueft alle drei Geraetevarianten, die Mindeststrom-Probe beim Anstecken, stabile Phasen waehrend einer Ladepause, die Schaltsperren, Fahrzeugstrom-Erkennung, die Leistungsangebote in PV und Peak sowie die Umschaltung ueber den `Solarladen`-Button. diff --git a/libs/LadestationRegler.php b/libs/LadestationRegler.php index bfbc176..c3886fa 100644 --- a/libs/LadestationRegler.php +++ b/libs/LadestationRegler.php @@ -15,6 +15,22 @@ final class LadestationRegler private const LEISTUNG_PRO_AMPERE_EINPHASIG = 230; private const LEISTUNG_PRO_AMPERE_DREIPHASIG = 684; + public static function erkennePhasenzahlAusLeistung( + float $leistung, + int $angeforderterStrom + ): int { + if (!is_finite($leistung) || $leistung < 0.0) { + throw new InvalidArgumentException('Istleistung muss endlich und darf nicht negativ sein.'); + } + if ($angeforderterStrom < 6 || $angeforderterStrom > 32) { + throw new InvalidArgumentException('Erkennungsstrom muss zwischen 6 und 32 A liegen.'); + } + + $trennleistung = 2 * self::LEISTUNG_PRO_AMPERE_EINPHASIG * $angeforderterStrom; + + return $leistung > $trennleistung ? self::PHASEN_DREI : self::PHASEN_EIN; + } + /** * Die Schwelle und der Zuschlag von 2.5 A stammen aus der Enelix-1-Ladestation. * Ein Ladeende wird erst nach zuvor gemessener Ladeleistung angenommen, damit diff --git a/tests/EaseeModuleStrukturTest.php b/tests/EaseeModuleStrukturTest.php index e16af2a..0de944e 100644 --- a/tests/EaseeModuleStrukturTest.php +++ b/tests/EaseeModuleStrukturTest.php @@ -70,6 +70,19 @@ final class EaseeModuleStrukturTest extends TestCase self::assertStringContainsString("'Phasenzahl'", $modul); self::assertStringNotContainsString('7500', $modul); self::assertStringNotContainsString('Abfrageintervall', $modul); + self::assertStringContainsString( + "RegisterVariableInteger('Fahrzeugstatus', 'Fahrzeugstatus', '', 200)", + $modul + ); + self::assertStringContainsString( + "RegisterVariableFloat('Istleistung', 'Istleistung', '', 170)", + $modul + ); + self::assertStringContainsString( + "RegisterVariableInteger('Sollleistung', 'Sollleistung', '', 180)", + $modul + ); + self::assertStringContainsString('RegeluebergangTimeout', $modul); self::assertStringContainsString("'action' => 'StartCharging'", $modul); $gateway = (string) file_get_contents( diff --git a/tests/LadestationReglerTest.php b/tests/LadestationReglerTest.php index 043313a..0b766b5 100644 --- a/tests/LadestationReglerTest.php +++ b/tests/LadestationReglerTest.php @@ -9,6 +9,24 @@ use PHPUnit\Framework\TestCase; final class LadestationReglerTest extends TestCase { + public function testPhasenprobeUnterscheidetBeiMindeststromOhneMaximalstromsprung(): void + { + self::assertSame( + LadestationRegler::PHASEN_EIN, + LadestationRegler::erkennePhasenzahlAusLeistung(1380.0, 6) + ); + self::assertSame( + LadestationRegler::PHASEN_DREI, + LadestationRegler::erkennePhasenzahlAusLeistung(4104.0, 6) + ); + } + + public function testPhasenprobeWeistUngueltigenErkennungsstromAb(): void + { + $this->expectException(\InvalidArgumentException::class); + LadestationRegler::erkennePhasenzahlAusLeistung(4104.0, 5); + } + public function testFahrzeugUndDreiPhasenWerdenWieInEnelixEinsErkannt(): void { $status = LadestationRegler::normalisiereStatus([ diff --git a/tests/LadestationStandAloneModulstrukturTest.php b/tests/LadestationStandAloneModulstrukturTest.php index 3b22a14..ffe2f5f 100644 --- a/tests/LadestationStandAloneModulstrukturTest.php +++ b/tests/LadestationStandAloneModulstrukturTest.php @@ -88,6 +88,20 @@ final class LadestationStandAloneModulstrukturTest extends TestCase self::assertStringContainsString("EnableAction('Solarladen')", $modul); self::assertStringContainsString("ReadPropertyBoolean('LoggingEin')", $modul); self::assertStringContainsString("ReadPropertyBoolean('EinstellungenInVisu')", $modul); + self::assertStringContainsString( + "RegisterVariableInteger('Fahrzeugstatus', 'Fahrzeugstatus', '', 200)", + $modul + ); + self::assertStringContainsString( + "RegisterVariableFloat('Istleistung', 'Istleistung', '', 170)", + $modul + ); + self::assertStringContainsString( + "RegisterVariableInteger('Sollleistung', 'Sollleistung', '', 180)", + $modul + ); + self::assertStringContainsString('RegeluebergangTimeout', $modul); + self::assertStringContainsString('PHASENERKENNUNGSSTROM = 6', $modul); self::assertStringContainsString('UnregisterVariable($ident)', $modul); } } diff --git a/tests/Symcon/modules/LadestationGateway.php b/tests/Symcon/modules/LadestationGateway.php index d1716f6..679a3a3 100644 --- a/tests/Symcon/modules/LadestationGateway.php +++ b/tests/Symcon/modules/LadestationGateway.php @@ -184,6 +184,58 @@ return static function (TestContext $test): void { $test->assertInstanceStatus($station); }); + $test->runCase('Solarumschaltung wartet auf die neue Manager-Vorgabe', static function ( + TestContext $test + ) use ($station): void { + $managerId = $test->createInstance( + '{6F771B18-59D4-4C8A-B951-3B2FE9F6A2C4}', + 'Hilfsmanager Easee-Uebergang', + [ + 'AutomatischeSuche' => false, + 'VerbraucherZuordnung' => json_encode([ + ['InstanzID' => $station, 'Aktiv' => true], + ], JSON_THROW_ON_ERROR), + ] + ); + $sendeSollwert = static function (int $leistung) use ($managerId, $station): void { + IPS_RequestAction($station, 'ManagerdatenEmpfangen', json_encode([ + 'Kopf' => [ + 'Version' => '4.0', + 'AbsenderID' => $managerId, + 'EmpfaengerID' => $station, + 'Zeitpunkt' => time(), + ], + 'Betriebsart' => 'PV', + 'Sollleistung_W' => $leistung, + ], JSON_THROW_ON_ERROR)); + }; + + $sendeSollwert(4104); + $befehlVorUmschaltung = (string) GetValue( + $test->objectByIdent('LetzterGeraetebefehl', $station) + ); + IPS_RequestAction($station, 'Solarladen', false); + + $test->assertSame( + $befehlVorUmschaltung, + (string) GetValue($test->objectByIdent('LetzterGeraetebefehl', $station)) + ); + $test->assertSame( + 4104, + GetValue($test->objectByIdent('Sollleistung', $station)), + 'Die Sollleistung muss bis zur neuen Manager-Vorgabe stabil bleiben.' + ); + + $sendeSollwert(10944); + $test->assertTrue(str_contains( + (string) GetValue($test->objectByIdent('LetzterGeraetebefehl', $station)), + '"Ampere":16' + )); + + IPS_RequestAction($station, 'Solarladen', true); + $sendeSollwert(0); + }); + $test->runCase('SignalR-Abbruch erreicht die Ladestation', static function ( TestContext $test ) use ($gateway, $station): void { @@ -226,4 +278,24 @@ return static function (TestContext $test): void { ); $test->assertInstanceStatus($station, 202); }); + + $test->runCase('Leistungswerte und Fahrzeugstatus folgen ihrer Sichtbarkeitsgruppe', static function ( + TestContext $test + ) use ($station): void { + IPS_SetProperty($station, 'EinstellungenInVisu', true); + IPS_SetProperty($station, 'DiagnosevariablenAnzeigen', false); + IPS_ApplyChanges($station); + + $test->assertTrue(@IPS_GetObjectIDByIdent('Istleistung', $station) !== false); + $test->assertTrue(@IPS_GetObjectIDByIdent('Sollleistung', $station) !== false); + $test->assertSame(false, @IPS_GetObjectIDByIdent('Fahrzeugstatus', $station)); + + IPS_SetProperty($station, 'EinstellungenInVisu', false); + IPS_SetProperty($station, 'DiagnosevariablenAnzeigen', true); + IPS_ApplyChanges($station); + + $test->assertSame(false, @IPS_GetObjectIDByIdent('Istleistung', $station)); + $test->assertSame(false, @IPS_GetObjectIDByIdent('Sollleistung', $station)); + $test->assertTrue(@IPS_GetObjectIDByIdent('Fahrzeugstatus', $station) !== false); + }); }; diff --git a/tests/Symcon/modules/LadestationStandAlone.php b/tests/Symcon/modules/LadestationStandAlone.php index 9e9b3df..6509ef3 100644 --- a/tests/Symcon/modules/LadestationStandAlone.php +++ b/tests/Symcon/modules/LadestationStandAlone.php @@ -361,7 +361,18 @@ return static function (TestContext $test): void { 'amp=6' ), 'Solarladen: Der 6-A-Befehl fehlt. Erhalten: ' . $befehl . '; Diagnose: ' . $diagnose); + $befehlVorUmschaltung = $befehl; IPS_RequestAction($stationId, 'Solarladen', false); + $test->assertSame( + $befehlVorUmschaltung, + (string) GetValue($test->objectByIdent('LetzterGeraetebefehl', $stationId)), + 'Die Umschaltung darf vor der neuen Manager-Vorgabe keinen Zwischenwert setzen.' + ); + $test->assertSame( + 4104, + GetValue($test->objectByIdent('Sollleistung', $stationId)), + 'Die Sollleistung muss bis zur neuen Manager-Vorgabe stabil bleiben.' + ); $angebot = (string) GetValue($test->objectByIdent('LeistungsangebotDiagnose', $stationId)); $test->assertSame('[10944]', $angebot, 'PV ohne Solarladen muss nur das Maximum anbieten.'); $abgewiesen = false; @@ -422,7 +433,7 @@ return static function (TestContext $test): void { )); }); - $test->runCase('Neue Ladestation wird erst nach Freigabe mit Maximalstrom erkannt', static function ( + $test->runCase('Neue Ladestation wird erst nach Freigabe mit Mindeststrom erkannt', static function ( TestContext $test ) use ($phasenerkennung, $anforderungSenden): void { $stationId = $phasenerkennung; @@ -432,8 +443,8 @@ return static function (TestContext $test): void { ); $test->assertTrue(!str_contains( (string) GetValue($test->objectByIdent('LetzterGeraetebefehl', $stationId)), - 'amp=16' - ), 'Eine inaktive Station darf keine Maximalstrom-Probe starten.'); + 'amp=6' + ), 'Eine inaktive Station darf keine Phasenprobe starten.'); IPS_RequestAction($stationId, 'Aktiv', true); @@ -443,8 +454,8 @@ return static function (TestContext $test): void { ); $test->assertTrue(str_contains( (string) GetValue($test->objectByIdent('LetzterGeraetebefehl', $stationId)), - 'amp=16' - ), 'Nach der Freigabe muss die Maximalstrom-Probe starten.'); + 'amp=6' + ), 'Nach der Freigabe muss die Mindeststrom-Phasenprobe starten.'); IPS_Sleep(2100); IPS_RequestAction($stationId, 'Statuszyklus', false); @@ -472,4 +483,25 @@ return static function (TestContext $test): void { (string) GetValue($test->objectByIdent('LeistungsangebotDiagnose', $stationId)) ); }); + + $test->runCase('Leistungswerte und Fahrzeugstatus folgen ihrer Sichtbarkeitsgruppe', static function ( + TestContext $test + ) use ($stationen): void { + $stationId = $stationen['go-e alt']; + IPS_SetProperty($stationId, 'EinstellungenInVisu', true); + IPS_SetProperty($stationId, 'DiagnosevariablenAnzeigen', false); + IPS_ApplyChanges($stationId); + + $test->assertTrue(@IPS_GetObjectIDByIdent('Istleistung', $stationId) !== false); + $test->assertTrue(@IPS_GetObjectIDByIdent('Sollleistung', $stationId) !== false); + $test->assertSame(false, @IPS_GetObjectIDByIdent('Fahrzeugstatus', $stationId)); + + IPS_SetProperty($stationId, 'EinstellungenInVisu', false); + IPS_SetProperty($stationId, 'DiagnosevariablenAnzeigen', true); + IPS_ApplyChanges($stationId); + + $test->assertSame(false, @IPS_GetObjectIDByIdent('Istleistung', $stationId)); + $test->assertSame(false, @IPS_GetObjectIDByIdent('Sollleistung', $stationId)); + $test->assertTrue(@IPS_GetObjectIDByIdent('Fahrzeugstatus', $stationId) !== false); + }); };