diff --git a/LadestationStandAlone/module.php b/LadestationStandAlone/module.php index 6258dcd..5e37852 100644 --- a/LadestationStandAlone/module.php +++ b/LadestationStandAlone/module.php @@ -100,6 +100,7 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell $this->RegisterAttributeInteger('PhasenerkennungSeit', 0); $this->RegisterAttributeInteger('PhasenerkennungVersion', 0); $this->RegisterAttributeBoolean('LadeleistungSeitFreigabeErkannt', false); + $this->RegisterAttributeInteger('GeraeteMaximalstrom', 32); $this->RegisterAttributeInteger('ErkannterMaximalstrom', 32); $this->RegisterAttributeInteger('FahrzeugstromKandidat', 0); $this->RegisterAttributeInteger('FahrzeugstromKandidatSeit', 0); @@ -236,7 +237,6 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell if ((bool) $wert) { $this->SetTimerInterval('RueckmeldungVerzoegert', 0); } - $this->aktualisiere(false); $this->sendeVerbraucherdaten(); return; @@ -315,6 +315,7 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell $phasenzahl = $this->ReadAttributeInteger('ZustandPhasenzahl'); $maximalstrom = min( $this->ReadPropertyInteger('MaximalerLadestrom'), + max(6, $this->ReadAttributeInteger('GeraeteMaximalstrom')), max(6, $this->ReadAttributeInteger('ErkannterMaximalstrom')) ); $this->setzeSichtbareVariable('FahrzeugMaximalstrom', $maximalstrom); @@ -423,6 +424,15 @@ class LadestationStandAlone extends IPSModule implements VerbraucherSchnittstell $this->ReadPropertyInteger('Geraetetyp'), $antwort ); + if (isset($rohstatus['Sollstrom_A'])) { + $geraeteSollstrom = (int) $rohstatus['Sollstrom_A']; + if ($geraeteSollstrom === 0 || ($geraeteSollstrom >= 6 && $geraeteSollstrom <= 32)) { + $this->WriteAttributeInteger('LetzterGesetzterStrom', $geraeteSollstrom); + } + } + if (isset($rohstatus['Maximalstrom_A'])) { + $this->WriteAttributeInteger('GeraeteMaximalstrom', (int) $rohstatus['Maximalstrom_A']); + } $warVerbunden = $this->ReadAttributeBoolean('ZustandFahrzeugVerbunden'); $verbunden = $rohstatus['Rohstatus'] !== 1; diff --git a/Manager/module.php b/Manager/module.php index d956413..8c9b984 100644 --- a/Manager/module.php +++ b/Manager/module.php @@ -219,6 +219,11 @@ class Manager extends IPSModule implements ManagerSchnittstelle 0, "IPS_RequestAction(\$_IPS['TARGET'], 'Regeln', true);" ); + $this->RegisterTimer( + 'RegelungVerzoegert', + 0, + "IPS_RequestAction(\$_IPS['TARGET'], 'RegelnVerzoegert', false);" + ); $this->RegisterTimer( 'PrognoseSenden', 0, @@ -252,6 +257,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle $this->SetTimerInterval('Regelzyklus', 0); $this->SetTimerInterval('VorgabenErneuern', 0); $this->SetTimerInterval('KeepAlive', 0); + $this->SetTimerInterval('RegelungVerzoegert', 0); $this->SetTimerInterval('PrognoseSenden', 0); $this->SetTimerInterval('StoerungenSenden', 0); $this->SetTimerInterval('MesswerteAufzeichnen', 0); @@ -263,6 +269,7 @@ class Manager extends IPSModule implements ManagerSchnittstelle $this->SetTimerInterval('Regelzyklus', 0); $this->SetTimerInterval('VorgabenErneuern', 0); $this->SetTimerInterval('KeepAlive', $this->ReadPropertyInteger('KeepAlive') * 1000); + $this->SetTimerInterval('RegelungVerzoegert', 0); $this->SetTimerInterval('PrognoseSenden', 0); $this->SetTimerInterval( 'StoerungenSenden', @@ -456,6 +463,11 @@ class Manager extends IPSModule implements ManagerSchnittstelle $this->regeln((bool) $wert); return; + case 'RegelnVerzoegert': + $this->SetTimerInterval('RegelungVerzoegert', 0); + $this->regeln(false); + return; + case 'PrognoseSenden': $this->sendePrognoseTelemetrie(); return; @@ -624,9 +636,9 @@ class Manager extends IPSModule implements ManagerSchnittstelle $this->WriteAttributeString('VerbraucherCache', json_encode($cache, JSON_THROW_ON_ERROR)); $this->aktualisiereEnergieflusswerte(); $this->aktualisiereDiagrammMesswerte(); - if ($this->GetBuffer('VerbraucherSynchronisierungAktiv') !== '1') { - $this->regeln(false); - } + + // Den synchronen Rueckruf in die noch meldende Verbraucherinstanz vermeiden. + $this->SetTimerInterval('RegelungVerzoegert', 100); } /** @param array $daten */ diff --git a/libs/LadestationAdapter.php b/libs/LadestationAdapter.php index 322cfaf..832e78d 100644 --- a/libs/LadestationAdapter.php +++ b/libs/LadestationAdapter.php @@ -91,7 +91,7 @@ final class LadestationAdapter } /** - * @return array{Rohstatus: int, Istleistung_W: float, Iststrom_A?: float, Phasenzahl?: int} + * @return array{Rohstatus: int, Istleistung_W: float, Sollstrom_A?: int, Maximalstrom_A?: int, Iststrom_A?: float, Phasenzahl?: int} */ public static function dekodiereStatus(int $geraetetyp, string $antwort): array { @@ -115,6 +115,20 @@ final class LadestationAdapter 'Rohstatus' => (int) $daten['car'], 'Istleistung_W' => (float) $daten['nrg'][11] * $leistungsfaktor, ]; + if (isset($daten['amp']) && is_numeric($daten['amp'])) { + $sollstrom = (int) $daten['amp']; + $freigabeEntzogen = isset($daten['alw']) && $daten['alw'] === false; + $erzwungenAus = $geraetetyp === self::GO_E_GEMINI + && isset($daten['frc']) + && (int) $daten['frc'] === 1; + $status['Sollstrom_A'] = $freigabeEntzogen || $erzwungenAus ? 0 : $sollstrom; + } + if (isset($daten['ama']) && is_numeric($daten['ama'])) { + $maximalstrom = (int) $daten['ama']; + if ($maximalstrom >= 6 && $maximalstrom <= 32) { + $status['Maximalstrom_A'] = $maximalstrom; + } + } if (isset($daten['nrg'][4], $daten['nrg'][5], $daten['nrg'][6]) && is_numeric($daten['nrg'][4]) && is_numeric($daten['nrg'][5]) diff --git a/tests/LadestationAdapterTest.php b/tests/LadestationAdapterTest.php index 194b09a..4d48235 100644 --- a/tests/LadestationAdapterTest.php +++ b/tests/LadestationAdapterTest.php @@ -13,7 +13,7 @@ final class LadestationAdapterTest extends TestCase /** * @dataProvider statusFaelle * @param array $konfiguration - * @param array{Rohstatus: int, Istleistung_W: float, Iststrom_A?: float, Phasenzahl?: int} $erwartet + * @param array{Rohstatus: int, Istleistung_W: float, Sollstrom_A?: int, Maximalstrom_A?: int, Iststrom_A?: float, Phasenzahl?: int} $erwartet */ public function testStatusaufrufUndDekodierungFuerAlleGeraete( int $geraetetyp, @@ -52,6 +52,8 @@ final class LadestationAdapterTest extends TestCase [ 'Rohstatus' => 2, 'Istleistung_W' => 11000.0, + 'Sollstrom_A' => 16, + 'Maximalstrom_A' => 16, 'Iststrom_A' => 16.0, 'Phasenzahl' => 3, ], @@ -64,6 +66,8 @@ final class LadestationAdapterTest extends TestCase [ 'Rohstatus' => 2, 'Istleistung_W' => 2300.0, + 'Sollstrom_A' => 16, + 'Maximalstrom_A' => 16, 'Iststrom_A' => 9.8, 'Phasenzahl' => 1, ], @@ -81,6 +85,20 @@ final class LadestationAdapterTest extends TestCase ]; } + public function testGoEAusFreigabeWirdAlsNullSollstromDekodiert(): void + { + $daten = json_decode($this->goEAntwort(2, 0, [0, 0, 0]), true, 512, JSON_THROW_ON_ERROR); + $daten['alw'] = false; + $daten['frc'] = 1; + + $status = LadestationAdapter::dekodiereStatus( + LadestationAdapter::GO_E_GEMINI, + json_encode($daten, JSON_THROW_ON_ERROR) + ); + + self::assertSame(0, $status['Sollstrom_A']); + } + /** * @dataProvider steuerFaelle * @param array $konfiguration @@ -180,6 +198,13 @@ final class LadestationAdapterTest extends TestCase } $nrg[11] = $leistung; - return json_encode(['car' => $status, 'nrg' => $nrg], JSON_THROW_ON_ERROR); + return json_encode([ + 'car' => $status, + 'nrg' => $nrg, + 'amp' => 16, + 'ama' => 16, + 'alw' => true, + 'frc' => 2, + ], JSON_THROW_ON_ERROR); } } diff --git a/tests/LadestationStandAloneModulstrukturTest.php b/tests/LadestationStandAloneModulstrukturTest.php index ffe2f5f..8824618 100644 --- a/tests/LadestationStandAloneModulstrukturTest.php +++ b/tests/LadestationStandAloneModulstrukturTest.php @@ -104,4 +104,32 @@ final class LadestationStandAloneModulstrukturTest extends TestCase self::assertStringContainsString('PHASENERKENNUNGSSTROM = 6', $modul); self::assertStringContainsString('UnregisterVariable($ident)', $modul); } + + public function testMeldezyklusSendetDenBereitsGelesenenZustandOhneZusaetzlichenHttpAbruf(): void + { + $modul = (string) file_get_contents(self::MODULPFAD . 'module.php'); + self::assertSame(1, preg_match( + "/case 'Melden':(?.*?)case 'ManagerdatenEmpfangen':/s", + $modul, + $treffer + )); + self::assertStringContainsString('$this->sendeVerbraucherdaten();', $treffer['block']); + self::assertStringNotContainsString('$this->aktualisiere(', $treffer['block']); + } + + public function testVomGeraetBestaetigterSollstromWirdFuerWiederholungVerwendet(): void + { + $modul = (string) file_get_contents(self::MODULPFAD . 'module.php'); + + self::assertStringContainsString("\$rohstatus['Sollstrom_A']", $modul); + self::assertStringContainsString( + "WriteAttributeInteger('LetzterGesetzterStrom', \$geraeteSollstrom)", + $modul + ); + self::assertStringContainsString("RegisterAttributeInteger('GeraeteMaximalstrom', 32)", $modul); + self::assertStringContainsString( + "WriteAttributeInteger('GeraeteMaximalstrom', (int) \$rohstatus['Maximalstrom_A'])", + $modul + ); + } } diff --git a/tests/ManagerModulstrukturTest.php b/tests/ManagerModulstrukturTest.php index 7d49efd..3a6d5c9 100644 --- a/tests/ManagerModulstrukturTest.php +++ b/tests/ManagerModulstrukturTest.php @@ -380,4 +380,25 @@ final class ManagerModulstrukturTest extends TestCase self::assertStringContainsString('VerbraucherdatenEmpfangen(array $daten)', $inhalt); self::assertStringContainsString("'ManagerdatenEmpfangen'", $inhalt); } + + public function testVerbrauchermeldungPlantRegelungOhneSynchronenRueckruf(): void + { + $inhalt = (string) file_get_contents(__DIR__ . '/../Manager/module.php'); + self::assertStringContainsString( + "RegisterTimer(\n 'RegelungVerzoegert'", + $inhalt + ); + self::assertStringContainsString("case 'RegelnVerzoegert':", $inhalt); + self::assertSame(1, preg_match( + '/public function VerbraucherdatenEmpfangen\(array \$daten\): void(?.*?)' + . 'private function aktualisiereVerbraucherEnergie/s', + $inhalt, + $treffer + )); + self::assertStringContainsString( + "SetTimerInterval('RegelungVerzoegert', 100)", + $treffer['block'] + ); + self::assertStringNotContainsString('$this->regeln(false);', $treffer['block']); + } }