no message
This commit is contained in:
@@ -17,6 +17,6 @@ Jeder Aufruf der Ladestationsinstanz wird sofort als
|
||||
Version wird dabei `minutes: 0` gesendet. Das Gateway puffert, begrenzt oder
|
||||
wiederholt die Stromvorgabe nicht selbst.
|
||||
|
||||
Der benötigte WebSocket-Client wird nach dem Speichern der Easee-Zugangsdaten
|
||||
automatisch erstellt und konfiguriert. Im WebSocket-Client muss keine URL
|
||||
eingetragen werden.
|
||||
Der benötigte WebSocket-Client wird beim Erstellen des Gateways automatisch
|
||||
und genau einmal angelegt. Nach dem Speichern der Easee-Zugangsdaten wird er
|
||||
konfiguriert. Im WebSocket-Client muss keine URL eingetragen werden.
|
||||
|
||||
+14
-16
@@ -37,6 +37,11 @@ class EaseeGateway extends IPSModule
|
||||
'IPS_RequestAction(' . $this->InstanceID . ', "RefreshToken", 0);'
|
||||
);
|
||||
|
||||
// Ein Splitter benötigt einen eigenen I/O-Parent. RequireParent()
|
||||
// prüft zuerst die bestehende Verbindung und erzeugt daher beim
|
||||
// Instanzieren keine zweite WebSocket-Verbindung.
|
||||
$this->RequireParent(self::WEBSOCKET_MODULE_ID);
|
||||
|
||||
}
|
||||
|
||||
public function ApplyChanges()
|
||||
@@ -88,28 +93,21 @@ class EaseeGateway extends IPSModule
|
||||
$instance = IPS_GetInstance($this->InstanceID);
|
||||
$parentID = (int)$instance["ConnectionID"];
|
||||
|
||||
if ($parentID > 0) {
|
||||
$parent = IPS_GetInstance($parentID);
|
||||
if ($parent["ModuleInfo"]["ModuleID"] === self::WEBSOCKET_MODULE_ID) {
|
||||
return true;
|
||||
}
|
||||
IPS_DisconnectInstance($this->InstanceID);
|
||||
}
|
||||
|
||||
$parentID = IPS_CreateInstance(self::WEBSOCKET_MODULE_ID);
|
||||
if ($parentID <= 0) {
|
||||
if ($parentID <= 0 && !$this->RequireParent(self::WEBSOCKET_MODULE_ID)) {
|
||||
$this->SetLastError("WebSocket-Client konnte nicht erstellt werden");
|
||||
return false;
|
||||
}
|
||||
|
||||
IPS_SetName($parentID, "Easee SignalR WebSocket");
|
||||
$objectParentID = IPS_GetParent($this->InstanceID);
|
||||
if ($objectParentID > 0) {
|
||||
IPS_SetParent($parentID, $objectParentID);
|
||||
$instance = IPS_GetInstance($this->InstanceID);
|
||||
$parentID = (int)$instance["ConnectionID"];
|
||||
if ($parentID <= 0 || !IPS_InstanceExists($parentID)) {
|
||||
$this->SetLastError("WebSocket-Client ist nicht verbunden");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IPS_ConnectInstance($this->InstanceID, $parentID)) {
|
||||
$this->SetLastError("WebSocket-Client konnte nicht verbunden werden");
|
||||
$parent = IPS_GetInstance($parentID);
|
||||
if ($parent["ModuleInfo"]["ModuleID"] !== self::WEBSOCKET_MODULE_ID) {
|
||||
$this->SetLastError("Ungültige WebSocket-Schnittstelle");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+13
-9
@@ -28,7 +28,7 @@ Das Gateway liefert:
|
||||
Bei Easee erfolgt die Fahrzeug- und Phasenerkennung ohne den zeitbasierten
|
||||
`Pending_Counter`. Der maximale Ladestrom wird aus Observation 47 übernommen
|
||||
und zusätzlich durch `Max_Current_abs` begrenzt. Die Typen 1 bis 4 verwenden
|
||||
weiterhin unverändert die bisherige zeit- und leistungsbasierte Erkennung.
|
||||
weiterhin die adaptive Soll-/Istleistungserkennung mit dem `Pending_Counter`.
|
||||
Die Fahrzeugphasen werden anhand der tatsächlich gemessenen Leiterströme
|
||||
erkannt; alte Phasenwerte werden beim Trennen oder Neuverbinden verworfen.
|
||||
Während einer Ladepause mit 0 W bleibt die zuletzt erkannte Phasenanzahl
|
||||
@@ -48,21 +48,25 @@ 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.
|
||||
Ist die angeforderte Ladeleistung während 90 Sekunden um den Faktor `1.11`
|
||||
höher als die tatsächliche Leistung, wird der fahrzeugseitige Maximalstrom
|
||||
aus dem Istwert neu berechnet. Fällt er unter 6 A, wird `Auto fertig geladen`
|
||||
gesetzt. Bei einer durch das Modul angeforderten 0-W-Pause wird der
|
||||
`Pending_Counter` zurückgesetzt. Zusätzlich muss bei Go-E die Ladung
|
||||
freigegeben sein und der Fahrzeugstatus 4 anliegen.
|
||||
|
||||
### Smart-Me Pico
|
||||
|
||||
Typ 3 erkennt ein verbundenes Fahrzeug über den Pico-Ladestatus. Die
|
||||
Phasenerkennung verwendet `CurrentL1`, `CurrentL2` und `CurrentL3` des
|
||||
Smart-Me-Geräte-Endpunkts. Der maximale Stationsstrom wird direkt aus den
|
||||
Pico-Ladedaten übernommen.
|
||||
Pico-Ladedaten übernommen. Der fahrzeugseitige Maximalstrom und das Ladeende
|
||||
werden weiterhin über den 90-Sekunden-Soll-/Istvergleich ermittelt.
|
||||
|
||||
Bei Typ 1 bis 3 entfällt die zeitbasierte Fahrzeug- und Phasenerkennung über
|
||||
den `Pending_Counter`. Die Phasenzahl wird aktualisiert, sobald ein messbarer
|
||||
Ladestrom fließt. Beim Abstecken werden die erkannten Phasen zurückgesetzt.
|
||||
Bei Typ 1 bis 3 entfällt nur die frühere zeitbasierte Phasenerkennung. Die
|
||||
Phasenzahl wird direkt aus den API-Messwerten aktualisiert, sobald ein
|
||||
messbarer Ladestrom fließt. Beim Abstecken werden die erkannten Phasen
|
||||
zurückgesetzt. Die adaptive Maximalstrom- und Ladeenderkennung bleibt aktiv.
|
||||
|
||||
Typ 4 bleibt unverändert.
|
||||
|
||||
|
||||
+84
-53
@@ -468,9 +468,11 @@ class Ladestation extends IPSModule
|
||||
return $stationType === 5 || $stationType === 6;
|
||||
}
|
||||
|
||||
private function UsesDirectStationDetection(int $stationType): bool
|
||||
private function UsesAdaptiveCurrentDetection(int $stationType): bool
|
||||
{
|
||||
return in_array($stationType, [1, 2, 3, 5, 6], true);
|
||||
// Easee (5/6) liefert den Ladeendestatus direkt über das Gateway.
|
||||
// Alle anderen Typen benötigen weiterhin die Erkennung über Soll-/Istleistung.
|
||||
return in_array($stationType, [1, 2, 3, 4], true);
|
||||
}
|
||||
|
||||
private function ApplyEaseeGatewayResponse($response)
|
||||
@@ -716,14 +718,15 @@ class Ladestation extends IPSModule
|
||||
): bool {
|
||||
$wasDetected = $this->GetValue("Car_detected");
|
||||
$wasOnePhase = $this->GetValue("Is_1_ph");
|
||||
$currentMax = (float)$this->GetValue("Max_Current");
|
||||
|
||||
if ($resetPendingCounter) {
|
||||
$this->SetValue("Pending_Counter", 0);
|
||||
}
|
||||
$this->SetValue("Max_Current", $maxCurrent);
|
||||
|
||||
if (!$carDetected) {
|
||||
$this->SetValue("Pending_Counter", 0);
|
||||
$this->SetValue("Max_Current", $maxCurrent);
|
||||
$this->SetValue("Car_detected", false);
|
||||
$this->SetValue("Car_is_full", false);
|
||||
$this->SetValue("Leistung_Delta", 0);
|
||||
@@ -740,10 +743,18 @@ class Ladestation extends IPSModule
|
||||
$this->SetValue("Is_1_ph", $isOnePhase);
|
||||
}
|
||||
|
||||
$phaseChanged = $wasOnePhase !== $this->GetValue("Is_1_ph");
|
||||
if (!$wasDetected || $phaseChanged || $currentMax <= 0) {
|
||||
$this->SetValue("Max_Current", $maxCurrent);
|
||||
} else {
|
||||
// Einen vom Soll-/Istvergleich gelernten Fahrzeuggrenzwert nicht
|
||||
// bei jedem API-Abruf wieder mit dem Stationsgrenzwert überschreiben.
|
||||
$this->SetValue("Max_Current", min($currentMax, $maxCurrent));
|
||||
}
|
||||
|
||||
$this->SetValue("Car_detected", true);
|
||||
$this->SetValue("Car_is_full", $carIsFull);
|
||||
|
||||
$phaseChanged = $wasOnePhase !== $this->GetValue("Is_1_ph");
|
||||
if (!$wasDetected || $phaseChanged) {
|
||||
if ($this->GetValue("Is_1_ph")) {
|
||||
$power = $this->GetValue("Mindestaldestrom") * 230;
|
||||
@@ -813,7 +824,6 @@ class Ladestation extends IPSModule
|
||||
is_numeric($chargingPowerWatts) &&
|
||||
abs((float)$chargingPowerWatts) >= 100
|
||||
) {
|
||||
$this->SetValue("Pending_Counter", 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -828,21 +838,15 @@ class Ladestation extends IPSModule
|
||||
!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;
|
||||
// Der zentrale Soll-/Istvergleich setzt Max_Current nach 90 Sekunden.
|
||||
// Unter 6 A entspricht dies der bisherigen Erkennung "Auto geladen".
|
||||
$learnedMaxCurrent = (float)$this->GetValue("Max_Current");
|
||||
return $this->GetValue("Car_detected") &&
|
||||
$learnedMaxCurrent > 0 &&
|
||||
$learnedMaxCurrent < 6;
|
||||
}
|
||||
|
||||
private function DetectGoECar(int $stationType): bool
|
||||
@@ -862,6 +866,10 @@ class Ladestation extends IPSModule
|
||||
}
|
||||
|
||||
$this->SetValue("Fahrzeugstatus", $carState);
|
||||
$this->SetBuffer(
|
||||
"GoEChargingEnabledFromStatus",
|
||||
$this->IsGoEChargingEnabled($data, $stationType) ? "1" : "0"
|
||||
);
|
||||
|
||||
$isOnePhase = null;
|
||||
$chargingPowerWatts = null;
|
||||
@@ -887,18 +895,23 @@ class Ladestation extends IPSModule
|
||||
}
|
||||
|
||||
$carDetected = in_array($carState, [2, 3, 4, 5], true);
|
||||
$stationMaxCurrent = $this->GetGoEMaxCurrent($data);
|
||||
$wasFull = $this->GetValue("Car_is_full");
|
||||
$carIsFull = $carDetected && $this->DetectGoEFullCharge(
|
||||
$data,
|
||||
$stationType,
|
||||
$carState,
|
||||
$chargingPowerWatts
|
||||
);
|
||||
if ($wasFull && !$carIsFull) {
|
||||
$this->SetValue("Max_Current", $stationMaxCurrent);
|
||||
}
|
||||
|
||||
return $this->ApplyDirectStationDetection(
|
||||
$carDetected,
|
||||
$carIsFull,
|
||||
$isOnePhase,
|
||||
$this->GetGoEMaxCurrent($data),
|
||||
$stationMaxCurrent,
|
||||
false
|
||||
);
|
||||
}
|
||||
@@ -932,10 +945,12 @@ class Ladestation extends IPSModule
|
||||
|
||||
$chargingPower = $chargingData["ActiveChargingPower"] ??
|
||||
$chargingData["activeChargingPower"] ?? null;
|
||||
$chargingPowerWatts = null;
|
||||
if (is_numeric($chargingPower)) {
|
||||
$chargingPowerWatts = (float)$chargingPower * 1000;
|
||||
$this->SetValue(
|
||||
"Ladeleistung_Effektiv",
|
||||
round((float)$chargingPower * 1000)
|
||||
round($chargingPowerWatts)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -968,11 +983,22 @@ class Ladestation extends IPSModule
|
||||
}
|
||||
}
|
||||
|
||||
$carDetected = in_array($stationState, [2, 3, 4, 6], true);
|
||||
$carIsFull = $this->GetValue("Car_is_full");
|
||||
if (!$carIsFull) {
|
||||
$learnedMaxCurrent = (float)$this->GetValue("Max_Current");
|
||||
$carIsFull = $carDetected &&
|
||||
$this->GetValue("Car_detected") &&
|
||||
$learnedMaxCurrent > 0 &&
|
||||
$learnedMaxCurrent < 6;
|
||||
}
|
||||
|
||||
return $this->ApplyDirectStationDetection(
|
||||
in_array($stationState, [2, 3, 4, 6], true),
|
||||
false,
|
||||
$carDetected,
|
||||
$carIsFull,
|
||||
$isOnePhase,
|
||||
$maxCurrent
|
||||
$maxCurrent,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1475,43 +1501,48 @@ class Ladestation extends IPSModule
|
||||
// PowerSteps in der RegisterVariable speichern
|
||||
SetValue($this->GetIDForIdent("PowerSteps"), json_encode($powerSteps));
|
||||
// Rückgabe der Powersteps
|
||||
if (!$this->UsesDirectStationDetection($this->ReadPropertyInteger("Ladestation"))) {
|
||||
$counter = $this->GetValue("Pending_Counter");
|
||||
$stationType = $this->ReadPropertyInteger("Ladestation");
|
||||
if ($this->UsesAdaptiveCurrentDetection($stationType)) {
|
||||
$requestedPower = max(0, (float)$this->GetValue("Aktuelle_Leistung"));
|
||||
$actualPower = abs((float)$this->GetValue("Ladeleistung_Effektiv"));
|
||||
$availableSteps = $this->Get_Array_From_Current(
|
||||
$this->GetValue("Is_1_ph"),
|
||||
$this->GetValue("Max_Current"),
|
||||
$this->GetValue("Aktuelle_Leistung"),
|
||||
$this->GetValue("IsTimerActive_Null_Timer")
|
||||
);
|
||||
$maxAvailablePower = count($availableSteps) > 0
|
||||
? max($availableSteps)
|
||||
: 0;
|
||||
$maxPowerStep = count($powerSteps) > 0 ? max($powerSteps) : 0;
|
||||
$goEEnabled = !in_array($stationType, [1, 2], true) ||
|
||||
$this->GetBuffer("GoEChargingEnabledFromStatus") === "1";
|
||||
$canEvaluate = $ladebereit &&
|
||||
$this->GetValue("Car_detected") &&
|
||||
!$this->GetValue("Car_is_full") &&
|
||||
$requestedPower > 0 &&
|
||||
$maxPowerStep > 0 &&
|
||||
$goEEnabled;
|
||||
|
||||
if($this->GetValue("Aktuelle_Leistung")>(1.11*$this->GetValue("Ladeleistung_Effektiv"))){
|
||||
$this->SetValue("Pending_Counter", $counter+1);
|
||||
|
||||
}elseif(max($this->Get_Array_From_Current($this->GetValue("Is_1_ph"),$this->GetValue("Max_Current"), $this->GetValue("Aktuelle_Leistung"), $this->GetValue("IsTimerActive_Null_Timer")))<(1.11*$this->GetValue("Ladeleistung_Effektiv"))){ // diesen elseif ggf wieder rauslöschen
|
||||
$this->SetValue("Pending_Counter", $counter+1);
|
||||
|
||||
}
|
||||
else{
|
||||
|
||||
$this->SetValue("Pending_Counter", 0);
|
||||
|
||||
}
|
||||
|
||||
if($counter>(90/($this->ReadPropertyInteger("Interval")))){
|
||||
|
||||
$this->SetValue("Pending_Counter", 0);
|
||||
|
||||
if((max(json_decode($this->GetValue("PowerSteps")))) >0){
|
||||
|
||||
if($this->GetValue("Aktuelle_Leistung")>(1.11*$this->GetValue("Ladeleistung_Effektiv"))) {
|
||||
|
||||
$this->Calc_Max_Current($this->GetValue("Is_1_ph"));
|
||||
$requestedMismatch = $requestedPower > (1.11 * $actualPower);
|
||||
$availableMismatch = $maxAvailablePower < (1.11 * $actualPower);
|
||||
|
||||
if ($canEvaluate && ($requestedMismatch || $availableMismatch)) {
|
||||
$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) {
|
||||
$this->SetValue("Pending_Counter", 0);
|
||||
if ($requestedMismatch) {
|
||||
$this->Calc_Max_Current($this->GetValue("Is_1_ph"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->SetValue("Pending_Counter", 0);
|
||||
}
|
||||
} elseif (!in_array(
|
||||
$this->ReadPropertyInteger("Ladestation"),
|
||||
[1, 2],
|
||||
true
|
||||
)) {
|
||||
} else {
|
||||
$this->SetValue("Pending_Counter", 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ Das Gateway liefert:
|
||||
Bei Easee erfolgt die Fahrzeug- und Phasenerkennung ohne den zeitbasierten
|
||||
`Pending_Counter`. Der maximale Ladestrom wird aus Observation 47 übernommen
|
||||
und zusätzlich durch `Max_Current_abs` begrenzt. Die Typen 1 bis 4 verwenden
|
||||
weiterhin unverändert die bisherige zeit- und leistungsbasierte Erkennung.
|
||||
weiterhin die adaptive Soll-/Istleistungserkennung mit dem `Pending_Counter`.
|
||||
Die Fahrzeugphasen werden anhand der tatsächlich gemessenen Leiterströme
|
||||
erkannt; alte Phasenwerte werden beim Trennen oder Neuverbinden verworfen.
|
||||
Während einer Ladepause mit 0 W bleibt die zuletzt erkannte Phasenanzahl
|
||||
@@ -48,21 +48,25 @@ 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.
|
||||
Ist die angeforderte Ladeleistung während 90 Sekunden um den Faktor `1.11`
|
||||
höher als die tatsächliche Leistung, wird der fahrzeugseitige Maximalstrom
|
||||
aus dem Istwert neu berechnet. Fällt er unter 6 A, wird `Auto fertig geladen`
|
||||
gesetzt. Bei einer durch das Modul angeforderten 0-W-Pause wird der
|
||||
`Pending_Counter` zurückgesetzt. Zusätzlich muss bei Go-E die Ladung
|
||||
freigegeben sein und der Fahrzeugstatus 4 anliegen.
|
||||
|
||||
### Smart-Me Pico
|
||||
|
||||
Typ 3 erkennt ein verbundenes Fahrzeug über den Pico-Ladestatus. Die
|
||||
Phasenerkennung verwendet `CurrentL1`, `CurrentL2` und `CurrentL3` des
|
||||
Smart-Me-Geräte-Endpunkts. Der maximale Stationsstrom wird direkt aus den
|
||||
Pico-Ladedaten übernommen.
|
||||
Pico-Ladedaten übernommen. Der fahrzeugseitige Maximalstrom und das Ladeende
|
||||
werden weiterhin über den 90-Sekunden-Soll-/Istvergleich ermittelt.
|
||||
|
||||
Bei Typ 1 bis 3 entfällt die zeitbasierte Fahrzeug- und Phasenerkennung über
|
||||
den `Pending_Counter`. Die Phasenzahl wird aktualisiert, sobald ein messbarer
|
||||
Ladestrom fließt. Beim Abstecken werden die erkannten Phasen zurückgesetzt.
|
||||
Bei Typ 1 bis 3 entfällt nur die frühere zeitbasierte Phasenerkennung. Die
|
||||
Phasenzahl wird direkt aus den API-Messwerten aktualisiert, sobald ein
|
||||
messbarer Ladestrom fließt. Beim Abstecken werden die erkannten Phasen
|
||||
zurückgesetzt. Die adaptive Maximalstrom- und Ladeenderkennung bleibt aktiv.
|
||||
|
||||
Typ 4 bleibt unverändert.
|
||||
|
||||
@@ -75,3 +79,5 @@ Typ 4 bleibt unverändert.
|
||||
`Schnittstelle ändern` die gewünschte Gateway-Instanz auswählen.
|
||||
|
||||
Mehrere Easee-Ladestationen desselben Kontos verwenden gemeinsam ein Gateway.
|
||||
Beim Erstellen einer weiteren Instanz wird ein vorhandenes Gateway automatisch
|
||||
verwendet; es wird keine zweite Parent-Verbindung erzeugt.
|
||||
|
||||
+93
-60
@@ -113,6 +113,10 @@ class Ladestation_v2 extends IPSModule
|
||||
$this->RegisterVariableInteger("Mindestaldestrom", "Mindestaldestrom", "", 0);
|
||||
$this->EnableAction("Mindestaldestrom");
|
||||
|
||||
// Vorhandenes Gateway verwenden; nur wenn keines existiert, wird eines
|
||||
// erstellt. ConnectParent() ist auch bei bereits gesetztem Parent sicher.
|
||||
$this->ConnectParent(self::EASEE_GATEWAY_MODULE_ID);
|
||||
|
||||
}
|
||||
|
||||
public function Migrate($JSONData)
|
||||
@@ -286,14 +290,12 @@ class Ladestation_v2 extends IPSModule
|
||||
$instance = IPS_GetInstance($this->InstanceID);
|
||||
$parentID = (int)$instance["ConnectionID"];
|
||||
|
||||
// Eine in Version 1.2/1.3 gespeicherte Gateway-Auswahl wieder als
|
||||
// normale IP-Symcon-Schnittstelle verbinden.
|
||||
// Bei einer aktualisierten, bisher noch unverbundenen Bestandsinstanz
|
||||
// die normale IP-Symcon-Parent-Verbindung nachziehen.
|
||||
if ($parentID <= 0) {
|
||||
$storedGatewayID = $this->GetConfiguredEaseeGatewayID();
|
||||
if ($storedGatewayID > 0) {
|
||||
IPS_ConnectInstance($this->InstanceID, $storedGatewayID);
|
||||
$parentID = $storedGatewayID;
|
||||
}
|
||||
$this->ConnectParent(self::EASEE_GATEWAY_MODULE_ID);
|
||||
$instance = IPS_GetInstance($this->InstanceID);
|
||||
$parentID = (int)$instance["ConnectionID"];
|
||||
}
|
||||
|
||||
if ($usesEaseeGateway && $this->IsEaseeGatewayInstance($parentID)) {
|
||||
@@ -486,9 +488,11 @@ class Ladestation_v2 extends IPSModule
|
||||
return $stationType === 5 || $stationType === 6;
|
||||
}
|
||||
|
||||
private function UsesDirectStationDetection(int $stationType): bool
|
||||
private function UsesAdaptiveCurrentDetection(int $stationType): bool
|
||||
{
|
||||
return in_array($stationType, [1, 2, 3, 5, 6], true);
|
||||
// Easee (5/6) liefert den Ladeendestatus direkt über das Gateway.
|
||||
// Alle anderen Typen benötigen weiterhin die Erkennung über Soll-/Istleistung.
|
||||
return in_array($stationType, [1, 2, 3, 4], true);
|
||||
}
|
||||
|
||||
private function ApplyEaseeGatewayResponse($response)
|
||||
@@ -734,14 +738,15 @@ class Ladestation_v2 extends IPSModule
|
||||
): bool {
|
||||
$wasDetected = $this->GetValue("Car_detected");
|
||||
$wasOnePhase = $this->GetValue("Is_1_ph");
|
||||
$currentMax = (float)$this->GetValue("Max_Current");
|
||||
|
||||
if ($resetPendingCounter) {
|
||||
$this->SetValue("Pending_Counter", 0);
|
||||
}
|
||||
$this->SetValue("Max_Current", $maxCurrent);
|
||||
|
||||
if (!$carDetected) {
|
||||
$this->SetValue("Pending_Counter", 0);
|
||||
$this->SetValue("Max_Current", $maxCurrent);
|
||||
$this->SetValue("Car_detected", false);
|
||||
$this->SetValue("Car_is_full", false);
|
||||
$this->SetValue("Leistung_Delta", 0);
|
||||
@@ -758,10 +763,18 @@ class Ladestation_v2 extends IPSModule
|
||||
$this->SetValue("Is_1_ph", $isOnePhase);
|
||||
}
|
||||
|
||||
$phaseChanged = $wasOnePhase !== $this->GetValue("Is_1_ph");
|
||||
if (!$wasDetected || $phaseChanged || $currentMax <= 0) {
|
||||
$this->SetValue("Max_Current", $maxCurrent);
|
||||
} else {
|
||||
// Einen vom Soll-/Istvergleich gelernten Fahrzeuggrenzwert nicht
|
||||
// bei jedem API-Abruf wieder mit dem Stationsgrenzwert überschreiben.
|
||||
$this->SetValue("Max_Current", min($currentMax, $maxCurrent));
|
||||
}
|
||||
|
||||
$this->SetValue("Car_detected", true);
|
||||
$this->SetValue("Car_is_full", $carIsFull);
|
||||
|
||||
$phaseChanged = $wasOnePhase !== $this->GetValue("Is_1_ph");
|
||||
if (!$wasDetected || $phaseChanged) {
|
||||
if ($this->GetValue("Is_1_ph")) {
|
||||
$power = $this->GetValue("Mindestaldestrom") * 230;
|
||||
@@ -831,7 +844,6 @@ class Ladestation_v2 extends IPSModule
|
||||
is_numeric($chargingPowerWatts) &&
|
||||
abs((float)$chargingPowerWatts) >= 100
|
||||
) {
|
||||
$this->SetValue("Pending_Counter", 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -846,21 +858,15 @@ class Ladestation_v2 extends IPSModule
|
||||
!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;
|
||||
// Der zentrale Soll-/Istvergleich setzt Max_Current nach 90 Sekunden.
|
||||
// Unter 6 A entspricht dies der bisherigen Erkennung "Auto geladen".
|
||||
$learnedMaxCurrent = (float)$this->GetValue("Max_Current");
|
||||
return $this->GetValue("Car_detected") &&
|
||||
$learnedMaxCurrent > 0 &&
|
||||
$learnedMaxCurrent < 6;
|
||||
}
|
||||
|
||||
private function DetectGoECar(int $stationType): bool
|
||||
@@ -880,6 +886,10 @@ class Ladestation_v2 extends IPSModule
|
||||
}
|
||||
|
||||
$this->SetValue("Fahrzeugstatus", $carState);
|
||||
$this->SetBuffer(
|
||||
"GoEChargingEnabledFromStatus",
|
||||
$this->IsGoEChargingEnabled($data, $stationType) ? "1" : "0"
|
||||
);
|
||||
|
||||
$isOnePhase = null;
|
||||
$chargingPowerWatts = null;
|
||||
@@ -905,18 +915,23 @@ class Ladestation_v2 extends IPSModule
|
||||
}
|
||||
|
||||
$carDetected = in_array($carState, [2, 3, 4, 5], true);
|
||||
$stationMaxCurrent = $this->GetGoEMaxCurrent($data);
|
||||
$wasFull = $this->GetValue("Car_is_full");
|
||||
$carIsFull = $carDetected && $this->DetectGoEFullCharge(
|
||||
$data,
|
||||
$stationType,
|
||||
$carState,
|
||||
$chargingPowerWatts
|
||||
);
|
||||
if ($wasFull && !$carIsFull) {
|
||||
$this->SetValue("Max_Current", $stationMaxCurrent);
|
||||
}
|
||||
|
||||
return $this->ApplyDirectStationDetection(
|
||||
$carDetected,
|
||||
$carIsFull,
|
||||
$isOnePhase,
|
||||
$this->GetGoEMaxCurrent($data),
|
||||
$stationMaxCurrent,
|
||||
false
|
||||
);
|
||||
}
|
||||
@@ -950,10 +965,12 @@ class Ladestation_v2 extends IPSModule
|
||||
|
||||
$chargingPower = $chargingData["ActiveChargingPower"] ??
|
||||
$chargingData["activeChargingPower"] ?? null;
|
||||
$chargingPowerWatts = null;
|
||||
if (is_numeric($chargingPower)) {
|
||||
$chargingPowerWatts = (float)$chargingPower * 1000;
|
||||
$this->SetValue(
|
||||
"Ladeleistung_Effektiv",
|
||||
round((float)$chargingPower * 1000)
|
||||
round($chargingPowerWatts)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -986,11 +1003,22 @@ class Ladestation_v2 extends IPSModule
|
||||
}
|
||||
}
|
||||
|
||||
$carDetected = in_array($stationState, [2, 3, 4, 6], true);
|
||||
$carIsFull = $this->GetValue("Car_is_full");
|
||||
if (!$carIsFull) {
|
||||
$learnedMaxCurrent = (float)$this->GetValue("Max_Current");
|
||||
$carIsFull = $carDetected &&
|
||||
$this->GetValue("Car_detected") &&
|
||||
$learnedMaxCurrent > 0 &&
|
||||
$learnedMaxCurrent < 6;
|
||||
}
|
||||
|
||||
return $this->ApplyDirectStationDetection(
|
||||
in_array($stationState, [2, 3, 4, 6], true),
|
||||
false,
|
||||
$carDetected,
|
||||
$carIsFull,
|
||||
$isOnePhase,
|
||||
$maxCurrent
|
||||
$maxCurrent,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1486,43 +1514,48 @@ class Ladestation_v2 extends IPSModule
|
||||
// PowerSteps in der RegisterVariable speichern
|
||||
SetValue($this->GetIDForIdent("PowerSteps"), json_encode($powerSteps));
|
||||
// Rückgabe der Powersteps
|
||||
if (!$this->UsesDirectStationDetection($this->ReadPropertyInteger("Ladestation"))) {
|
||||
$counter = $this->GetValue("Pending_Counter");
|
||||
$stationType = $this->ReadPropertyInteger("Ladestation");
|
||||
if ($this->UsesAdaptiveCurrentDetection($stationType)) {
|
||||
$requestedPower = max(0, (float)$this->GetValue("Aktuelle_Leistung"));
|
||||
$actualPower = abs((float)$this->GetValue("Ladeleistung_Effektiv"));
|
||||
$availableSteps = $this->Get_Array_From_Current(
|
||||
$this->GetValue("Is_1_ph"),
|
||||
$this->GetValue("Max_Current"),
|
||||
$this->GetValue("Aktuelle_Leistung"),
|
||||
$this->GetValue("IsTimerActive_Null_Timer")
|
||||
);
|
||||
$maxAvailablePower = count($availableSteps) > 0
|
||||
? max($availableSteps)
|
||||
: 0;
|
||||
$maxPowerStep = count($powerSteps) > 0 ? max($powerSteps) : 0;
|
||||
$goEEnabled = !in_array($stationType, [1, 2], true) ||
|
||||
$this->GetBuffer("GoEChargingEnabledFromStatus") === "1";
|
||||
$canEvaluate = $ladebereit &&
|
||||
$this->GetValue("Car_detected") &&
|
||||
!$this->GetValue("Car_is_full") &&
|
||||
$requestedPower > 0 &&
|
||||
$maxPowerStep > 0 &&
|
||||
$goEEnabled;
|
||||
|
||||
if($this->GetValue("Aktuelle_Leistung")>(1.11*$this->GetValue("Ladeleistung_Effektiv"))){
|
||||
$this->SetValue("Pending_Counter", $counter+1);
|
||||
|
||||
}elseif(max($this->Get_Array_From_Current($this->GetValue("Is_1_ph"),$this->GetValue("Max_Current"), $this->GetValue("Aktuelle_Leistung"), $this->GetValue("IsTimerActive_Null_Timer")))<(1.11*$this->GetValue("Ladeleistung_Effektiv"))){ // diesen elseif ggf wieder rauslöschen
|
||||
$this->SetValue("Pending_Counter", $counter+1);
|
||||
|
||||
}
|
||||
else{
|
||||
|
||||
$this->SetValue("Pending_Counter", 0);
|
||||
|
||||
}
|
||||
|
||||
if($counter>(90/($this->ReadPropertyInteger("Interval")))){
|
||||
|
||||
$this->SetValue("Pending_Counter", 0);
|
||||
|
||||
if((max(json_decode($this->GetValue("PowerSteps")))) >0){
|
||||
|
||||
if($this->GetValue("Aktuelle_Leistung")>(1.11*$this->GetValue("Ladeleistung_Effektiv"))) {
|
||||
|
||||
$this->Calc_Max_Current($this->GetValue("Is_1_ph"));
|
||||
$requestedMismatch = $requestedPower > (1.11 * $actualPower);
|
||||
$availableMismatch = $maxAvailablePower < (1.11 * $actualPower);
|
||||
|
||||
if ($canEvaluate && ($requestedMismatch || $availableMismatch)) {
|
||||
$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) {
|
||||
$this->SetValue("Pending_Counter", 0);
|
||||
if ($requestedMismatch) {
|
||||
$this->Calc_Max_Current($this->GetValue("Is_1_ph"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->SetValue("Pending_Counter", 0);
|
||||
}
|
||||
} elseif (!in_array(
|
||||
$this->ReadPropertyInteger("Ladestation"),
|
||||
[1, 2],
|
||||
true
|
||||
)) {
|
||||
} else {
|
||||
$this->SetValue("Pending_Counter", 0);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"id": "{89CAF37C-8E6E-5312-8195-6DA8AB7E5E70}",
|
||||
"name": "Manager",
|
||||
"author": "Daniel Haefliger",
|
||||
"url": "https://git.belevo.ch/dh/Symcon_Belevo_Energiemanagement",
|
||||
"url": "https://git.belevo.ch/dh/Symcon_Belevo_Energiemanagement_testing",
|
||||
"compatibility": {
|
||||
"version": "8.0"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user