This commit is contained in:
@@ -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.
|
||||
|
||||
+114
-54
@@ -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<string> */
|
||||
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);
|
||||
$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']) {
|
||||
$sollleistung = $this->bestimmeWirksameSollleistung($angebot);
|
||||
if ($steuerungAusfuehren && !$regeluebergangAktiv) {
|
||||
$this->setzeLadestrom(
|
||||
$this->bestimmeWirksameSollleistung($angebot),
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<string> */
|
||||
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':
|
||||
case 'Solarladen':
|
||||
$this->WriteAttributeBoolean('Zustand' . $ident, (bool) $wert);
|
||||
$this->setzeSichtbareVariable($ident, (bool) $wert);
|
||||
$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':
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user