$konfiguration * @return array */ public static function statusAnfrage(int $geraetetyp, array $konfiguration): array { if ($geraetetyp === self::GO_E_ALT) { return self::anfrage('GET', self::lokaleBasisUrl($konfiguration) . '/mqtt?payload='); } if ($geraetetyp === self::GO_E_GEMINI) { return self::anfrage('GET', self::lokaleBasisUrl($konfiguration) . '/api/status'); } if ($geraetetyp === self::SMART_ME_PICO) { $id = self::pflichtwert($konfiguration, 'GeraeteID'); return self::anfrage( 'GET', 'https://api.smart-me.com/pico/charging/' . rawurlencode($id), $konfiguration ); } throw new InvalidArgumentException('Unbekannter Geraetetyp.'); } /** * @param array $konfiguration * @return list> */ public static function steuerAnfragen( int $geraetetyp, array $konfiguration, int $ladestrom ): array { if ($ladestrom < 0 || $ladestrom > 32 || ($ladestrom > 0 && $ladestrom < 6)) { throw new InvalidArgumentException('Ladestrom muss 0 oder 6 bis 32 A betragen.'); } if ($geraetetyp === self::GO_E_ALT) { $basis = self::lokaleBasisUrl($konfiguration) . '/mqtt?payload='; if ($ladestrom === 0) { return [self::anfrage('GET', $basis . 'alw=0')]; } return [ self::anfrage('GET', $basis . 'alw=1'), self::anfrage('GET', $basis . 'amp=' . $ladestrom), ]; } if ($geraetetyp === self::GO_E_GEMINI) { $basis = self::lokaleBasisUrl($konfiguration) . '/api/set?'; if ($ladestrom === 0) { return [self::anfrage('GET', $basis . 'frc=1&sua=false')]; } return [ self::anfrage('GET', $basis . 'frc=2'), self::anfrage('GET', $basis . 'amp=' . $ladestrom), ]; } if ($geraetetyp === self::SMART_ME_PICO) { $seriennummer = self::pflichtwert($konfiguration, 'Seriennummer'); return [self::anfrage( 'POST', 'https://api.smart-me.com/pico/loadmanagementgroup/current/' . rawurlencode($seriennummer) . '?current=' . ($ladestrom * 1000), $konfiguration )]; } throw new InvalidArgumentException('Unbekannter Geraetetyp.'); } /** * @return array{Rohstatus: int, Istleistung_W: float} */ public static function dekodiereStatus(int $geraetetyp, string $antwort): array { $daten = json_decode($antwort, true, 512, JSON_THROW_ON_ERROR); if (!is_array($daten)) { throw new RuntimeException('Die Geraeteantwort ist kein JSON-Objekt.'); } if ($geraetetyp === self::GO_E_ALT || $geraetetyp === self::GO_E_GEMINI) { if (!isset($daten['car'], $daten['nrg']) || !is_numeric($daten['car']) || !is_array($daten['nrg']) || !isset($daten['nrg'][11]) || !is_numeric($daten['nrg'][11]) ) { throw new RuntimeException('Die go-e-Antwort enthaelt nicht alle Statusfelder.'); } $faktor = $geraetetyp === self::GO_E_ALT ? 10.0 : 1.0; return [ 'Rohstatus' => (int) $daten['car'], 'Istleistung_W' => (float) $daten['nrg'][11] * $faktor, ]; } if ($geraetetyp === self::SMART_ME_PICO) { if (!isset($daten['State'], $daten['ActiveChargingPower']) || !is_numeric($daten['State']) || !is_numeric($daten['ActiveChargingPower']) ) { throw new RuntimeException('Die Pico-Antwort enthaelt nicht alle Statusfelder.'); } return [ 'Rohstatus' => (int) $daten['State'], 'Istleistung_W' => round((float) $daten['ActiveChargingPower'] * 1000.0), ]; } throw new InvalidArgumentException('Unbekannter Geraetetyp.'); } /** * @param array $konfiguration * @return array */ private static function anfrage( string $methode, string $url, array $konfiguration = [] ): array { $anfrage = ['Methode' => $methode, 'URL' => $url]; if (str_starts_with($url, 'https://api.smart-me.com/')) { $anfrage['Benutzername'] = self::pflichtwert($konfiguration, 'Benutzername'); $anfrage['Passwort'] = self::pflichtwert($konfiguration, 'Passwort'); } return $anfrage; } /** @param array $konfiguration */ private static function lokaleBasisUrl(array $konfiguration): string { $adresse = trim(self::pflichtwert($konfiguration, 'Geraeteadresse')); if (str_contains($adresse, '/') || str_contains($adresse, '?')) { throw new InvalidArgumentException('Geraeteadresse muss ein Hostname oder eine IP-Adresse sein.'); } return 'http://' . $adresse; } /** @param array $konfiguration */ private static function pflichtwert(array $konfiguration, string $name): string { $wert = trim($konfiguration[$name] ?? ''); if ($wert === '') { throw new InvalidArgumentException($name . ' darf nicht leer sein.'); } return $wert; } } final class LadestationTransport { /** @var callable(array): string */ private $anfrageAusfuehren; /** @param callable(array): string $anfrageAusfuehren */ public function __construct(callable $anfrageAusfuehren) { $this->anfrageAusfuehren = $anfrageAusfuehren; } /** @param array $konfiguration */ public function statusLesen(int $geraetetyp, array $konfiguration): string { return ($this->anfrageAusfuehren)( LadestationAdapter::statusAnfrage($geraetetyp, $konfiguration) ); } /** @param array $konfiguration */ public function ladestromSetzen( int $geraetetyp, array $konfiguration, int $ladestrom ): void { foreach (LadestationAdapter::steuerAnfragen($geraetetyp, $konfiguration, $ladestrom) as $anfrage) { ($this->anfrageAusfuehren)($anfrage); } } }