diff --git a/CHANGELOG.md b/CHANGELOG.md index 563cb15..38b7ecb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ Alle wesentlichen Aenderungen an Enelix EMS werden in dieser Datei dokumentiert. - Stufenlose Leistungsbereiche fuer Batteriespeicher. - Ladefreigabe neuer Ladestationsinstanzen standardmaessig aktiviert. - Easee-Ladestationen laden einen fehlenden Initialstatus ueber die Observations-API nach und starten bei noch unbekannter Ausgangsphase konservativ einphasig. +- Wartende Easee-Ladestationen erhalten bei positiver Stromvorgabe einmal pro Fahrzeugverbindung einen Startbefehl; Freigabe- und Blockiergruende werden diagnostiziert. - Fehlende oder veraltete Verbraucher blockieren die Verteilung an aktuelle Verbraucher nicht mehr. - Die Stoerungsueberwachung fordert einen fehlenden Geraetezugang innerhalb ihres Retry-Zyklus automatisch neu an. - Vollstaendige PHP-, Struktur- und Symcon-Modultests fuer alle Module. diff --git a/EaseeGateway/module.php b/EaseeGateway/module.php index d491571..8144b02 100644 --- a/EaseeGateway/module.php +++ b/EaseeGateway/module.php @@ -221,6 +221,12 @@ class EaseeGateway extends IPSModule $seriennummer, (float) ($anfrage['amps'] ?? -1) ), JSON_THROW_ON_ERROR); + + case 'StartCharging': + return json_encode( + $this->sendeLadestart($seriennummer), + JSON_THROW_ON_ERROR + ); } return json_encode([ @@ -670,6 +676,24 @@ class EaseeGateway extends IPSModule ); } + /** @return array */ + private function sendeLadestart(string $seriennummer): array + { + if ($seriennummer === '') { + return ['success' => false, 'error' => 'Seriennummer fehlt.']; + } + if ($this->ReadPropertyBoolean('Testmodus')) { + return ['success' => true, 'httpCode' => 200, 'body' => '{}']; + } + + return $this->autorisierteApiAnfrage( + 'POST', + '/api/chargers/' . rawurlencode($seriennummer) + . '/commands/start_charging', + '' + ); + } + /** @return array */ private function autorisierteApiAnfrage( string $methode, diff --git a/LadestationGateway/module.php b/LadestationGateway/module.php index 4a1b18e..383b3f3 100644 --- a/LadestationGateway/module.php +++ b/LadestationGateway/module.php @@ -41,7 +41,13 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle 'Stoertext', 'GatewayVerbunden', 'ApiMaximalstrom', + 'EaseeAktiviert', + 'AutorisierungErforderlich', + 'RemoteStartErforderlich', + 'SmartCharging', + 'GrundKeinLadestrom', 'LetzterGeraetebefehl', + 'LetzterStartbefehl', 'LeistungsangebotDiagnose', ]; @@ -82,6 +88,11 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle $this->RegisterAttributeString('EaseeBeobachtungen', '{}'); $this->RegisterAttributeInteger('LetzteBeobachtung', 0); $this->RegisterAttributeInteger('ApiMaximalstrom', 16); + $this->RegisterAttributeBoolean('ZustandEaseeAktiviert', true); + $this->RegisterAttributeBoolean('ZustandAutorisierungErforderlich', false); + $this->RegisterAttributeBoolean('ZustandRemoteStartErforderlich', false); + $this->RegisterAttributeBoolean('ZustandSmartCharging', false); + $this->RegisterAttributeInteger('ZustandGrundKeinLadestrom', 0); $this->RegisterAttributeBoolean('ZustandFahrzeugVerbunden', false); $this->RegisterAttributeBoolean('ZustandFahrzeugGeladen', false); $this->RegisterAttributeInteger('ZustandFahrzeugstatus', 0); @@ -99,7 +110,9 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle $this->RegisterAttributeInteger('LetzteManagerID', 0); $this->RegisterAttributeInteger('LetzteVorgabeZeit', 0); $this->RegisterAttributeInteger('LetzterGesetzterStrom', -1); + $this->RegisterAttributeBoolean('LadestartFuerVerbindungGesendet', false); $this->RegisterAttributeString('LetzterGeraetebefehl', ''); + $this->RegisterAttributeString('LetzterStartbefehl', ''); $this->RegisterTimer( 'Meldezyklus', @@ -128,6 +141,7 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle $this->aktualisiereVariablen(); $this->WriteAttributeBoolean('GatewayVerbunden', false); $this->WriteAttributeInteger('LetzterGesetzterStrom', -1); + $this->WriteAttributeBoolean('LadestartFuerVerbindungGesendet', false); try { $this->pruefeKonfiguration(); @@ -405,6 +419,11 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle 'Phasenzahl', 'Istleistung_W', 'Ladestrom_A', + 'EaseeAktiviert', + 'AutorisierungErforderlich', + 'RemoteStartErforderlich', + 'SmartCharging', + 'GrundKeinLadestrom', ] as $feld) { $this->setzeZustand($feld, $status[$feld]); } @@ -416,6 +435,9 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle 'ApiMaximalstrom', $status['ApiMaximalstrom_A'] ); + if (!$status['FahrzeugVerbunden']) { + $this->WriteAttributeBoolean('LadestartFuerVerbindungGesendet', false); + } $gatewayVerbunden = $this->ReadAttributeBoolean('GatewayVerbunden'); $phaseGueltig = in_array($status['Phasenzahl'], [1, 3], true); @@ -423,6 +445,7 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle $phaseErforderlich = $status['Fahrzeugstatus'] === 3; $steuerbar = $gatewayVerbunden && $status['StatusGueltig'] + && $status['EaseeAktiviert'] && !$status['Stoerung'] && (!$phaseErforderlich || $phaseGueltig); @@ -473,7 +496,8 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle if ($gatewayVerbunden && $status['StatusGueltig']) { $this->setzeLadestrom( $this->bestimmeWirksameSollleistung($angebot), - $regelPhasenzahl + $regelPhasenzahl, + $status['Fahrzeugstatus'] === 2 ); } else { $this->WriteAttributeInteger('LetzterGesetzterStrom', -1); @@ -512,34 +536,64 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle return 0; } - private function setzeLadestrom(int $leistung, int $phasenzahl): void - { + private function setzeLadestrom( + int $leistung, + int $phasenzahl, + bool $wartetAufStart + ): void { $strom = $leistung === 0 ? 0 : LadestationRegler::stromFuerLeistung($leistung, $phasenzahl); - if ($strom === $this->ReadAttributeInteger('LetzterGesetzterStrom')) { - return; + if ($strom !== $this->ReadAttributeInteger('LetzterGesetzterStrom')) { + $antwort = $this->gatewayAnfrage([ + 'action' => 'SetDynamicChargerCurrent', + 'serialNumber' => $this->seriennummer(), + 'amps' => $strom, + ]); + if (!($antwort['success'] ?? false)) { + throw new RuntimeException( + (string) ($antwort['error'] ?? 'Easee-Stromvorgabe fehlgeschlagen.') + ); + } + + $befehl = json_encode([ + 'Aktion' => 'SetDynamicChargerCurrent', + 'Seriennummer' => $this->seriennummer(), + 'Ampere' => $strom, + ], JSON_THROW_ON_ERROR); + $this->WriteAttributeString('LetzterGeraetebefehl', $befehl); + $this->setzeSichtbareVariable('LetzterGeraetebefehl', $befehl); + $this->WriteAttributeInteger('LetzterGesetzterStrom', $strom); } + if ( + $strom > 0 + && $wartetAufStart + && !$this->ReadAttributeBoolean('LadestartFuerVerbindungGesendet') + ) { + $this->sendeLadestart(); + } + } + + private function sendeLadestart(): void + { $antwort = $this->gatewayAnfrage([ - 'action' => 'SetDynamicChargerCurrent', + 'action' => 'StartCharging', 'serialNumber' => $this->seriennummer(), - 'amps' => $strom, ]); if (!($antwort['success'] ?? false)) { throw new RuntimeException( - (string) ($antwort['error'] ?? 'Easee-Stromvorgabe fehlgeschlagen.') + (string) ($antwort['error'] ?? 'Easee-Ladestart fehlgeschlagen.') ); } $befehl = json_encode([ - 'Aktion' => 'SetDynamicChargerCurrent', + 'Aktion' => 'StartCharging', 'Seriennummer' => $this->seriennummer(), - 'Ampere' => $strom, ], JSON_THROW_ON_ERROR); - $this->WriteAttributeString('LetzterGeraetebefehl', $befehl); - $this->setzeSichtbareVariable('LetzterGeraetebefehl', $befehl); - $this->WriteAttributeInteger('LetzterGesetzterStrom', $strom); + $this->WriteAttributeBoolean('LadestartFuerVerbindungGesendet', true); + $this->WriteAttributeString('LetzterStartbefehl', $befehl); + $this->setzeSichtbareVariable('LetzterStartbefehl', $befehl); } private function seriennummer(): string @@ -650,6 +704,36 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle 'Wert' => $this->ReadAttributeBoolean('ZustandSolarladen'), 'Einheit' => '', ], + [ + 'Kennung' => 'EaseeAktiviert', + 'Art' => 'Status', + 'Wert' => (bool) $this->leseZustand('EaseeAktiviert'), + 'Einheit' => '', + ], + [ + 'Kennung' => 'AutorisierungErforderlich', + 'Art' => 'Status', + 'Wert' => (bool) $this->leseZustand('AutorisierungErforderlich'), + 'Einheit' => '', + ], + [ + 'Kennung' => 'RemoteStartErforderlich', + 'Art' => 'Status', + 'Wert' => (bool) $this->leseZustand('RemoteStartErforderlich'), + 'Einheit' => '', + ], + [ + 'Kennung' => 'SmartCharging', + 'Art' => 'Status', + 'Wert' => (bool) $this->leseZustand('SmartCharging'), + 'Einheit' => '', + ], + [ + 'Kennung' => 'GrundKeinLadestrom', + 'Art' => 'Status', + 'Wert' => (int) $this->leseZustand('GrundKeinLadestrom'), + 'Einheit' => '', + ], [ 'Kennung' => 'Ladefehler', 'Art' => 'Stoerung', @@ -815,17 +899,53 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle '', 210 ); + $this->RegisterVariableBoolean( + 'EaseeAktiviert', + 'Easee aktiviert', + '~Switch', + 220 + ); + $this->RegisterVariableBoolean( + 'AutorisierungErforderlich', + 'Autorisierung erforderlich', + '~Switch', + 230 + ); + $this->RegisterVariableBoolean( + 'RemoteStartErforderlich', + 'Remote-Start erforderlich', + '~Switch', + 240 + ); + $this->RegisterVariableBoolean( + 'SmartCharging', + 'Easee Smart Charging', + '~Switch', + 250 + ); + $this->RegisterVariableInteger( + 'GrundKeinLadestrom', + 'Grund kein Ladestrom', + '', + 260 + ); $this->RegisterVariableString( 'LetzterGeraetebefehl', 'Letzter Geraetebefehl', '', - 220 + 270 + ); + $this->RegisterVariableString( + 'LetzterStartbefehl', + 'Letzter Startbefehl', + '', + 280 ); $this->RegisterVariableString( 'LeistungsangebotDiagnose', 'Leistungsangebot', '', - 230 + 290 ); $this->SetValue( 'LeistungsangebotDiagnose', @@ -835,11 +955,16 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle 'LetzterGeraetebefehl', $this->ReadAttributeString('LetzterGeraetebefehl') ); + $this->SetValue( + 'LetzterStartbefehl', + $this->ReadAttributeString('LetzterStartbefehl') + ); foreach (self::DIAGNOSE_VARIABLEN as $ident) { if (!in_array($ident, [ 'GatewayVerbunden', 'ApiMaximalstrom', 'LetzterGeraetebefehl', + 'LetzterStartbefehl', 'LeistungsangebotDiagnose', ], true)) { $this->setzeSichtbareVariable($ident, $this->leseZustand($ident)); @@ -874,6 +999,10 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle switch ($ident) { case 'FahrzeugVerbunden': case 'FahrzeugGeladen': + case 'EaseeAktiviert': + case 'AutorisierungErforderlich': + case 'RemoteStartErforderlich': + case 'SmartCharging': case 'SollwertGueltig': case 'Verfuegbar': case 'AenderungMoeglich': @@ -882,6 +1011,7 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle break; case 'Fahrzeugstatus': case 'Phasenzahl': + case 'GrundKeinLadestrom': case 'Sollleistung': $this->WriteAttributeInteger('Zustand' . $ident, (int) $wert); break; @@ -917,6 +1047,10 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle if (in_array($ident, [ 'FahrzeugVerbunden', 'FahrzeugGeladen', + 'EaseeAktiviert', + 'AutorisierungErforderlich', + 'RemoteStartErforderlich', + 'SmartCharging', 'SollwertGueltig', 'Verfuegbar', 'AenderungMoeglich', @@ -927,6 +1061,7 @@ class LadestationGateway extends IPSModule implements VerbraucherSchnittstelle if (in_array($ident, [ 'Fahrzeugstatus', 'Phasenzahl', + 'GrundKeinLadestrom', 'Sollleistung', ], true)) { return $this->ReadAttributeInteger('Zustand' . $ident); diff --git a/docs/module/Ladestation-Gateway/README.md b/docs/module/Ladestation-Gateway/README.md index ff21307..cb29912 100644 --- a/docs/module/Ladestation-Gateway/README.md +++ b/docs/module/Ladestation-Gateway/README.md @@ -58,12 +58,15 @@ als ungueltig behandelt und ergeben bis zur gueltigen 1-/3-Phasenmeldung nur Immer sichtbar sind `Aktiv`, `FahrzeugVerbunden`, `FahrzeugGeladen`, `Fahrzeugstatus`, `Ladestrom` und `Phasenzahl`. Der normalisierte -Fahrzeugstatus ist `0` unbekannt, `1` getrennt, `2` bereit, `3` laedt, -`4` geladen oder `5` Fehler. +Fahrzeugstatus ist `0` unbekannt, `1` getrennt, `2` wartet auf Start, +`3` laedt, `4` geladen oder `5` Fehler. Optional sichtbar sind die gemeinsamen EMS-Diagnosewerte sowie -`GatewayVerbunden`, `ApiMaximalstrom`, `LetzterGeraetebefehl` und -`LeistungsangebotDiagnose`. +`GatewayVerbunden`, `ApiMaximalstrom`, `EaseeAktiviert`, +`AutorisierungErforderlich`, `RemoteStartErforderlich`, `SmartCharging`, +`GrundKeinLadestrom`, `LetzterGeraetebefehl`, `LetzterStartbefehl` und +`LeistungsangebotDiagnose`. `GrundKeinLadestrom=55` bedeutet bei Easee, dass +die Autorisierung fehlt. ## Regelung @@ -83,7 +86,10 @@ Angebot sofort neu und meldet die Aenderung kurz gebuendelt an den Manager. 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` -an Easee gesendet. +an Easee gesendet. Meldet Easee bei positiver Stromvorgabe weiterhin +`Awaiting Start`, sendet das Modul einmal pro Fahrzeugverbindung zusaetzlich +`start_charging`. Dieser Befehl autorisiert den Ladevorgang, uebersteuert aber +keinen vorhandenen Easee-Ladeplan. ## Managerkommunikation diff --git a/libs/EaseeGatewayProtokoll.php b/libs/EaseeGatewayProtokoll.php index 9af91bd..8d61e40 100644 --- a/libs/EaseeGatewayProtokoll.php +++ b/libs/EaseeGatewayProtokoll.php @@ -8,7 +8,8 @@ final class EaseeGatewayProtokoll { /** @var list */ public const BEOBACHTUNGEN = [ - 47, 48, 100, 104, 109, 110, 119, 120, 182, 183, 184, 185, 250, + 31, 41, 42, 43, 47, 48, 62, 96, 100, 102, 104, 109, 110, + 111, 112, 113, 114, 119, 120, 182, 183, 184, 185, 250, ]; public static function seriennummer(string $wert): string diff --git a/libs/EaseeLadestatus.php b/libs/EaseeLadestatus.php index bf0737d..200fab4 100644 --- a/libs/EaseeLadestatus.php +++ b/libs/EaseeLadestatus.php @@ -22,6 +22,11 @@ final class EaseeLadestatus * Istleistung_W: float, * Ladestrom_A: float, * ApiMaximalstrom_A: int, + * EaseeAktiviert: bool, + * AutorisierungErforderlich: bool, + * RemoteStartErforderlich: bool, + * SmartCharging: bool, + * GrundKeinLadestrom: int, * Stoerung: bool, * Stoertext: string * } @@ -65,6 +70,16 @@ final class EaseeLadestatus } } $apiMaximalstrom = max(6, min($grenzen)); + $easeeAktiviert = !array_key_exists('31', $beobachtungen) + || (bool) $beobachtungen['31']; + $autorisierungErforderlich = (bool) ( + $beobachtungen['42'] ?? $beobachtungen['41'] ?? false + ); + $remoteStartErforderlich = (bool) ($beobachtungen['43'] ?? false); + $smartCharging = (bool) ($beobachtungen['102'] ?? false); + $grundKeinLadestrom = is_numeric($beobachtungen['96'] ?? null) + ? (int) $beobachtungen['96'] + : 0; $fehlercode = (int) ($beobachtungen['119'] ?? 0); $stoerung = $betriebszustand === 5 || $fehlercode !== 0; @@ -85,6 +100,11 @@ final class EaseeLadestatus 'Istleistung_W' => $leistung, 'Ladestrom_A' => $ladestrom, 'ApiMaximalstrom_A' => $apiMaximalstrom, + 'EaseeAktiviert' => $easeeAktiviert, + 'AutorisierungErforderlich' => $autorisierungErforderlich, + 'RemoteStartErforderlich' => $remoteStartErforderlich, + 'SmartCharging' => $smartCharging, + 'GrundKeinLadestrom' => $grundKeinLadestrom, 'Stoerung' => $stoerung, 'Stoertext' => trim($stoertext), ]; diff --git a/tests/EaseeGatewayProtokollTest.php b/tests/EaseeGatewayProtokollTest.php index 9d96e8b..7dc2418 100644 --- a/tests/EaseeGatewayProtokollTest.php +++ b/tests/EaseeGatewayProtokollTest.php @@ -58,6 +58,24 @@ final class EaseeGatewayProtokollTest extends TestCase ], $beobachtungen); } + public function testFreigabediagnoseWirdAusBeobachtungenExtrahiert(): void + { + $beobachtungen = EaseeGatewayProtokoll::extrahiereBeobachtungen([ + 'serialNumber' => 'EH123456', + 'observations' => [ + ['id' => 42, 'value' => true], + ['id' => 43, 'value' => true], + ['id' => 96, 'value' => 55], + ], + ], ['EH123456']); + + self::assertSame([ + ['Seriennummer' => 'EH123456', 'ID' => 42, 'Wert' => true], + ['Seriennummer' => 'EH123456', 'ID' => 43, 'Wert' => true], + ['Seriennummer' => 'EH123456', 'ID' => 96, 'Wert' => 55], + ], $beobachtungen); + } + public function testSeriennummerWirdNormalisiert(): void { self::assertSame( diff --git a/tests/EaseeLadestatusTest.php b/tests/EaseeLadestatusTest.php index 2f3f100..cb42878 100644 --- a/tests/EaseeLadestatusTest.php +++ b/tests/EaseeLadestatusTest.php @@ -89,6 +89,24 @@ final class EaseeLadestatusTest extends TestCase self::assertSame(13, $status['ApiMaximalstrom_A']); } + public function testFreigabeUndGrundOhneLadestromKommenAusEaseeBeobachtungen(): void + { + $status = EaseeLadestatus::ausBeobachtungen([ + '31' => true, + '42' => true, + '43' => true, + '96' => 55, + '102' => true, + '109' => 2, + ], 16); + + self::assertTrue($status['EaseeAktiviert']); + self::assertTrue($status['AutorisierungErforderlich']); + self::assertTrue($status['RemoteStartErforderlich']); + self::assertTrue($status['SmartCharging']); + self::assertSame(55, $status['GrundKeinLadestrom']); + } + public function testNurSolarladenIstFestErzwungen(): void { self::assertFalse(EaseeLadestatus::solarladenErzwungen(0)); diff --git a/tests/EaseeModuleStrukturTest.php b/tests/EaseeModuleStrukturTest.php index a94f0ef..e16af2a 100644 --- a/tests/EaseeModuleStrukturTest.php +++ b/tests/EaseeModuleStrukturTest.php @@ -70,6 +70,12 @@ final class EaseeModuleStrukturTest extends TestCase self::assertStringContainsString("'Phasenzahl'", $modul); self::assertStringNotContainsString('7500', $modul); self::assertStringNotContainsString('Abfrageintervall', $modul); + self::assertStringContainsString("'action' => 'StartCharging'", $modul); + + $gateway = (string) file_get_contents( + __DIR__ . '/../EaseeGateway/module.php' + ); + self::assertStringContainsString('/commands/start_charging', $gateway); } /** @return array */ diff --git a/tests/Symcon/modules/EaseeGateway.php b/tests/Symcon/modules/EaseeGateway.php index 449e385..e825613 100644 --- a/tests/Symcon/modules/EaseeGateway.php +++ b/tests/Symcon/modules/EaseeGateway.php @@ -72,6 +72,21 @@ return static function (TestContext $test): void { $test->assertSame(200, $antwort['httpCode']); }); + $test->runCase('Ladestart wird ueber Gateway angenommen', static function ( + TestContext $test + ) use ($gateway): void { + $antwort = json_decode(ENELIXEASEE_ProcessStationRequest( + $gateway, + json_encode([ + 'action' => 'StartCharging', + 'serialNumber' => 'EH123456', + ], JSON_THROW_ON_ERROR) + ), true, 512, JSON_THROW_ON_ERROR); + + $test->assertSame(true, $antwort['success']); + $test->assertSame(200, $antwort['httpCode']); + }); + $test->runCase('Gebrochene Stromvorgabe wird abgelehnt', static function ( TestContext $test ) use ($gateway): void { diff --git a/tests/Symcon/modules/LadestationGateway.php b/tests/Symcon/modules/LadestationGateway.php index d59b5f0..9df9062 100644 --- a/tests/Symcon/modules/LadestationGateway.php +++ b/tests/Symcon/modules/LadestationGateway.php @@ -111,6 +111,10 @@ return static function (TestContext $test): void { $test->runCase('Wartezustand startet konservativ ohne aktive Phase', static function ( TestContext $test ) use ($sendeBeobachtung, $station): void { + $sendeBeobachtung('EH123456', 42, true); + $sendeBeobachtung('EH123456', 43, true); + $sendeBeobachtung('EH123456', 96, 55); + $sendeBeobachtung('EH123456', 102, true); $sendeBeobachtung('EH123456', 109, 2); $sendeBeobachtung('EH123456', 110, 0); IPS_RequestAction($station, 'Solarladen', false); @@ -132,6 +136,20 @@ return static function (TestContext $test): void { ), '"Ampere":16' )); + $test->assertTrue(str_contains( + (string) GetValue( + $test->objectByIdent('LetzterStartbefehl', $station) + ), + '"Aktion":"StartCharging"' + )); + $test->assertSame( + 55, + GetValue($test->objectByIdent('GrundKeinLadestrom', $station)) + ); + $test->assertSame( + true, + GetValue($test->objectByIdent('AutorisierungErforderlich', $station)) + ); IPS_RequestAction($station, 'Solarladen', true); $sendeBeobachtung('EH123456', 110, 30);