diff --git a/Ladestation/README.md b/Ladestation/README.md index 1c74294..48da42e 100644 --- a/Ladestation/README.md +++ b/Ladestation/README.md @@ -48,6 +48,11 @@ Go-e-Fahrzeugstatus. Die tatsächlich verwendeten Phasen werden aus den drei gemessenen Strömen des `nrg`-Arrays bestimmt. Der maximale Ladestrom wird durch die Stations-, Kabel- und Modulgrenze begrenzt. +`Auto fertig geladen` wird bei Go-E erst gesetzt, wenn die Ladung freigegeben +ist, der Fahrzeugstatus 4 anliegt und während 90 Sekunden weniger als 100 W +fließen. Bei einer durch das Modul angeforderten 0-W-Pause wird der +`Pending_Counter` zurückgesetzt. Die Easee-Erkennung bleibt davon unberührt. + ### Smart-Me Pico Typ 3 erkennt ein verbundenes Fahrzeug über den Pico-Ladestatus. Die diff --git a/Ladestation/module.php b/Ladestation/module.php index 904c1b7..44c34d7 100644 --- a/Ladestation/module.php +++ b/Ladestation/module.php @@ -711,15 +711,19 @@ class Ladestation extends IPSModule bool $carDetected, bool $carIsFull, $isOnePhase, - float $maxCurrent + float $maxCurrent, + bool $resetPendingCounter = true ): bool { $wasDetected = $this->GetValue("Car_detected"); $wasOnePhase = $this->GetValue("Is_1_ph"); - $this->SetValue("Pending_Counter", 0); + if ($resetPendingCounter) { + $this->SetValue("Pending_Counter", 0); + } $this->SetValue("Max_Current", $maxCurrent); if (!$carDetected) { + $this->SetValue("Pending_Counter", 0); $this->SetValue("Car_detected", false); $this->SetValue("Car_is_full", false); $this->SetValue("Leistung_Delta", 0); @@ -777,6 +781,70 @@ class Ladestation extends IPSModule return $maxCurrent; } + private function IsGoEChargingEnabled(array $data, int $stationType): bool + { + if ($stationType === 1 && array_key_exists("alw", $data)) { + return (int)$data["alw"] === 1; + } + + if ($stationType === 2 && array_key_exists("frc", $data)) { + return (int)$data["frc"] === 2; + } + + if (array_key_exists("alw", $data)) { + return (int)$data["alw"] === 1; + } + + return $this->GetBuffer("GoEChargingEnabled") === "1"; + } + + private function DetectGoEFullCharge( + array $data, + int $stationType, + int $carState, + $chargingPowerWatts + ): bool { + $wasFull = $this->GetValue("Car_is_full"); + + // Ein einmal sicher erkanntes Ladeende bleibt bis zum Abstecken oder + // bis zu einer tatsächlich wieder aufgenommenen Ladung erhalten. + if ($wasFull) { + if ( + is_numeric($chargingPowerWatts) && + abs((float)$chargingPowerWatts) >= 100 + ) { + $this->SetValue("Pending_Counter", 0); + return false; + } + + return true; + } + + // car=4 alleine ist nicht ausreichend: Go-E meldet diesen Status auch, + // wenn die Regelung die Ladung absichtlich unterbricht. + if ( + $carState !== 4 || + !$this->IsGoEChargingEnabled($data, $stationType) || + !is_numeric($chargingPowerWatts) || + abs((float)$chargingPowerWatts) >= 100 + ) { + $this->SetValue("Pending_Counter", 0); + return false; + } + + $counter = $this->GetValue("Pending_Counter") + 1; + $this->SetValue("Pending_Counter", $counter); + + $interval = max(1, $this->ReadPropertyInteger("Interval")); + $requiredCycles = max(1, (int)ceil(90 / $interval)); + if ($counter < $requiredCycles) { + return false; + } + + $this->SetValue("Pending_Counter", 0); + return true; + } + private function DetectGoECar(int $stationType): bool { $path = $stationType === 1 ? "/mqtt?payload=" : "/api/status"; @@ -796,6 +864,7 @@ class Ladestation extends IPSModule $this->SetValue("Fahrzeugstatus", $carState); $isOnePhase = null; + $chargingPowerWatts = null; if (isset($data["nrg"]) && is_array($data["nrg"])) { $currentFactor = $stationType === 1 ? 0.1 : 1.0; $phaseCurrents = []; @@ -809,18 +878,28 @@ class Ladestation extends IPSModule if (isset($data["nrg"][11]) && is_numeric($data["nrg"][11])) { $powerFactor = $stationType === 1 ? 10 : 1; + $chargingPowerWatts = (float)$data["nrg"][11] * $powerFactor; $this->SetValue( "Ladeleistung_Effektiv", - round((float)$data["nrg"][11] * $powerFactor) + round($chargingPowerWatts) ); } } + $carDetected = in_array($carState, [2, 3, 4, 5], true); + $carIsFull = $carDetected && $this->DetectGoEFullCharge( + $data, + $stationType, + $carState, + $chargingPowerWatts + ); + return $this->ApplyDirectStationDetection( - in_array($carState, [2, 3, 4, 5], true), - $carState === 4, + $carDetected, + $carIsFull, $isOnePhase, - $this->GetGoEMaxCurrent($data) + $this->GetGoEMaxCurrent($data), + false ); } @@ -1428,7 +1507,11 @@ class Ladestation extends IPSModule } } - } else { + } elseif (!in_array( + $this->ReadPropertyInteger("Ladestation"), + [1, 2], + true + )) { $this->SetValue("Pending_Counter", 0); } @@ -1490,6 +1573,9 @@ class Ladestation extends IPSModule curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); + if (($stationType === 1 || $stationType === 2) && $response !== false) { + $this->SetBuffer("GoEChargingEnabled", "0"); + } curl_close($ch); return $response; } elseif ($value >= 1 && $value <= 32) { @@ -1531,6 +1617,9 @@ class Ladestation extends IPSModule curl_close($ch); return "Error:" . curl_error($ch); } + if ($stationType === 1 || $stationType === 2) { + $this->SetBuffer("GoEChargingEnabled", "1"); + } curl_close($ch); return; } else { diff --git a/Ladestation_v2/README.md b/Ladestation_v2/README.md index 75ef068..8dd6652 100644 --- a/Ladestation_v2/README.md +++ b/Ladestation_v2/README.md @@ -48,6 +48,11 @@ Go-e-Fahrzeugstatus. Die tatsächlich verwendeten Phasen werden aus den drei gemessenen Strömen des `nrg`-Arrays bestimmt. Der maximale Ladestrom wird durch die Stations-, Kabel- und Modulgrenze begrenzt. +`Auto fertig geladen` wird bei Go-E erst gesetzt, wenn die Ladung freigegeben +ist, der Fahrzeugstatus 4 anliegt und während 90 Sekunden weniger als 100 W +fließen. Bei einer durch das Modul angeforderten 0-W-Pause wird der +`Pending_Counter` zurückgesetzt. Die Easee-Erkennung bleibt davon unberührt. + ### Smart-Me Pico Typ 3 erkennt ein verbundenes Fahrzeug über den Pico-Ladestatus. Die diff --git a/Ladestation_v2/module.php b/Ladestation_v2/module.php index 2681e8b..a2f353d 100644 --- a/Ladestation_v2/module.php +++ b/Ladestation_v2/module.php @@ -729,15 +729,19 @@ class Ladestation_v2 extends IPSModule bool $carDetected, bool $carIsFull, $isOnePhase, - float $maxCurrent + float $maxCurrent, + bool $resetPendingCounter = true ): bool { $wasDetected = $this->GetValue("Car_detected"); $wasOnePhase = $this->GetValue("Is_1_ph"); - $this->SetValue("Pending_Counter", 0); + if ($resetPendingCounter) { + $this->SetValue("Pending_Counter", 0); + } $this->SetValue("Max_Current", $maxCurrent); if (!$carDetected) { + $this->SetValue("Pending_Counter", 0); $this->SetValue("Car_detected", false); $this->SetValue("Car_is_full", false); $this->SetValue("Leistung_Delta", 0); @@ -795,6 +799,70 @@ class Ladestation_v2 extends IPSModule return $maxCurrent; } + private function IsGoEChargingEnabled(array $data, int $stationType): bool + { + if ($stationType === 1 && array_key_exists("alw", $data)) { + return (int)$data["alw"] === 1; + } + + if ($stationType === 2 && array_key_exists("frc", $data)) { + return (int)$data["frc"] === 2; + } + + if (array_key_exists("alw", $data)) { + return (int)$data["alw"] === 1; + } + + return $this->GetBuffer("GoEChargingEnabled") === "1"; + } + + private function DetectGoEFullCharge( + array $data, + int $stationType, + int $carState, + $chargingPowerWatts + ): bool { + $wasFull = $this->GetValue("Car_is_full"); + + // Ein einmal sicher erkanntes Ladeende bleibt bis zum Abstecken oder + // bis zu einer tatsächlich wieder aufgenommenen Ladung erhalten. + if ($wasFull) { + if ( + is_numeric($chargingPowerWatts) && + abs((float)$chargingPowerWatts) >= 100 + ) { + $this->SetValue("Pending_Counter", 0); + return false; + } + + return true; + } + + // car=4 alleine ist nicht ausreichend: Go-E meldet diesen Status auch, + // wenn die Regelung die Ladung absichtlich unterbricht. + if ( + $carState !== 4 || + !$this->IsGoEChargingEnabled($data, $stationType) || + !is_numeric($chargingPowerWatts) || + abs((float)$chargingPowerWatts) >= 100 + ) { + $this->SetValue("Pending_Counter", 0); + return false; + } + + $counter = $this->GetValue("Pending_Counter") + 1; + $this->SetValue("Pending_Counter", $counter); + + $interval = max(1, $this->ReadPropertyInteger("Interval")); + $requiredCycles = max(1, (int)ceil(90 / $interval)); + if ($counter < $requiredCycles) { + return false; + } + + $this->SetValue("Pending_Counter", 0); + return true; + } + private function DetectGoECar(int $stationType): bool { $path = $stationType === 1 ? "/mqtt?payload=" : "/api/status"; @@ -814,6 +882,7 @@ class Ladestation_v2 extends IPSModule $this->SetValue("Fahrzeugstatus", $carState); $isOnePhase = null; + $chargingPowerWatts = null; if (isset($data["nrg"]) && is_array($data["nrg"])) { $currentFactor = $stationType === 1 ? 0.1 : 1.0; $phaseCurrents = []; @@ -827,18 +896,28 @@ class Ladestation_v2 extends IPSModule if (isset($data["nrg"][11]) && is_numeric($data["nrg"][11])) { $powerFactor = $stationType === 1 ? 10 : 1; + $chargingPowerWatts = (float)$data["nrg"][11] * $powerFactor; $this->SetValue( "Ladeleistung_Effektiv", - round((float)$data["nrg"][11] * $powerFactor) + round($chargingPowerWatts) ); } } + $carDetected = in_array($carState, [2, 3, 4, 5], true); + $carIsFull = $carDetected && $this->DetectGoEFullCharge( + $data, + $stationType, + $carState, + $chargingPowerWatts + ); + return $this->ApplyDirectStationDetection( - in_array($carState, [2, 3, 4, 5], true), - $carState === 4, + $carDetected, + $carIsFull, $isOnePhase, - $this->GetGoEMaxCurrent($data) + $this->GetGoEMaxCurrent($data), + false ); } @@ -1439,7 +1518,11 @@ class Ladestation_v2 extends IPSModule } } - } else { + } elseif (!in_array( + $this->ReadPropertyInteger("Ladestation"), + [1, 2], + true + )) { $this->SetValue("Pending_Counter", 0); } @@ -1501,6 +1584,9 @@ class Ladestation_v2 extends IPSModule curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); + if (($stationType === 1 || $stationType === 2) && $response !== false) { + $this->SetBuffer("GoEChargingEnabled", "0"); + } curl_close($ch); return $response; } elseif ($value >= 1 && $value <= 32) { @@ -1542,6 +1628,9 @@ class Ladestation_v2 extends IPSModule curl_close($ch); return "Error:" . curl_error($ch); } + if ($stationType === 1 || $stationType === 2) { + $this->SetBuffer("GoEChargingEnabled", "1"); + } curl_close($ch); return; } else {