no message
This commit is contained in:
+64
-40
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"elements": [
|
"elements": [
|
||||||
{
|
{
|
||||||
"type": "Label",
|
"type": "Label",
|
||||||
"caption": "Aufgepasst: Bei Goodwe nur Ladenvariabel auswählen und entladen Dummy Variabel.\nGoodwe braucht nur eine Leistungssoll Variabel. Entlade NICHT auf gleiche Variabel setzen wie Laden\nGoodwe: Laden=11, Entladen=12,\nSolaredge: Laden=3, Entladen=4\nDefault: Laden=1, Entladen=2"
|
"caption": "Aufgepasst: Bei Goodwe nur Ladenvariabel auswählen und entladen Dummy Variabel.\nGoodwe braucht nur eine Leistungssoll Variabel. Entlade NICHT auf gleiche Variabel setzen wie Laden\nGoodwe: Laden=11, Entladen=12,\nSolaredge: Laden=3, Entladen=4\nDefault: Laden=1, Entladen=2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "List",
|
"type": "List",
|
||||||
"name": "Batteries",
|
"name": "Batteries",
|
||||||
@@ -95,17 +95,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"caption": "Min. SoC",
|
"caption": "Min. SoC",
|
||||||
"name": "minPhysicalSocPct",
|
"name": "minPhysicalSocPct",
|
||||||
"width": "100px",
|
"width": "100px",
|
||||||
"suffix": " %",
|
"suffix": " %",
|
||||||
"add": 5,
|
"add": 5,
|
||||||
"edit": {
|
"edit": {
|
||||||
"type": "NumberSpinner",
|
"type": "NumberSpinner",
|
||||||
"minimum": 0,
|
"minimum": 0,
|
||||||
"maximum": 30,
|
"maximum": 30,
|
||||||
"digits": 1
|
"digits": 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"values": []
|
"values": []
|
||||||
@@ -131,13 +131,13 @@
|
|||||||
"digits": 0
|
"digits": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "NumberSpinner",
|
"type": "NumberSpinner",
|
||||||
"name": "ReserveHours",
|
"name": "ReserveHours",
|
||||||
"caption": "SDL Reservezeit",
|
"caption": "SDL Reservezeit",
|
||||||
"suffix": " h",
|
"suffix": " h",
|
||||||
"minimum": 0,
|
"minimum": 0,
|
||||||
"maximum": 24,
|
"maximum": 24,
|
||||||
"digits": 2
|
"digits": 2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "NumberSpinner",
|
"type": "NumberSpinner",
|
||||||
@@ -167,42 +167,66 @@
|
|||||||
"type": "NumberSpinner",
|
"type": "NumberSpinner",
|
||||||
"name": "UpdateInterval",
|
"name": "UpdateInterval",
|
||||||
"caption": "Update Intervall",
|
"caption": "Update Intervall",
|
||||||
"suffix": "S",
|
"suffix": " s",
|
||||||
"minimum": 1,
|
"minimum": 1,
|
||||||
|
"digits": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Label",
|
||||||
|
"caption": "EV-SoC Nachberechnung:\n\nAlle X Stunden wird geprüft, ob der virtuelle SDL-SoC bei 50% liegt.\nWenn ja, wird der EV-SoC anhand der physischen Batterie-SoCs neu berechnet.\nDie EV-Toleranz verhindert kleine unnötige Korrekturen.\n\n0 Stunden = automatische EV-Neuberechnung deaktiviert."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "NumberSpinner",
|
||||||
|
"name": "EV_Recalc_IntervalHours",
|
||||||
|
"caption": "EV SoC neu berechnen alle",
|
||||||
|
"suffix": " h",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 168,
|
||||||
|
"digits": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "NumberSpinner",
|
||||||
|
"name": "EV_Recalc_TolerancePct",
|
||||||
|
"caption": "EV Recalc Toleranz",
|
||||||
|
"suffix": " %",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 100,
|
||||||
"digits": 2
|
"digits": 2
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"type": "CheckBox",
|
"type": "CheckBox",
|
||||||
"name": "FilterAktiv",
|
"name": "FilterAktiv",
|
||||||
"caption": "Filter für aktuelle EV/SDL Leistung aktiv. Dient für die Visualisierung, um Leistungssprünge zu vermeiden."
|
"caption": "Filter für aktuelle EV/SDL Leistung aktiv. Dient für die Visualisierung, um Leistungssprünge zu vermeiden."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Label",
|
"type": "Label",
|
||||||
"caption": "Filter für aktuelle Leistung:\n\nToleranz (%): Wie stark der Istwert vom Soll abweichen darf\nRampe (W/s): Wie schnell die Leistung verändert wird (Trägheit)\nTreffer: Wie oft ein Wert passen muss, bevor er übernommen wird\n\n→ Höhere Rampe = schneller, aber sprunghafter\n→ Niedrigere Rampe = ruhiger, aber träger"
|
"caption": "Filter für aktuelle Leistung:\n\nToleranz (%): Wie stark der Istwert vom Soll abweichen darf\nRampe (W/s): Wie schnell die Leistung verändert wird (Trägheit)\nTreffer: Wie oft ein Wert passen muss, bevor er übernommen wird\n\n→ Höhere Rampe = schneller, aber sprunghafter\n→ Niedrigere Rampe = ruhiger, aber träger"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "NumberSpinner",
|
"type": "NumberSpinner",
|
||||||
"name": "FilterTolerancePct",
|
"name": "FilterTolerancePct",
|
||||||
"caption": "Filter Toleranz (%)",
|
"caption": "Filter Toleranz",
|
||||||
"minimum": 0,
|
"suffix": " %",
|
||||||
"maximum": 100,
|
"minimum": 0,
|
||||||
"digits": 1
|
"maximum": 100,
|
||||||
|
"digits": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "NumberSpinner",
|
"type": "NumberSpinner",
|
||||||
"name": "FilterRampWPerSec",
|
"name": "FilterRampWPerSec",
|
||||||
"caption": "Filter Rampe (W/s)",
|
"caption": "Filter Rampe",
|
||||||
"minimum": 100,
|
"suffix": " W/s",
|
||||||
"maximum": 20000,
|
"minimum": 100,
|
||||||
"digits": 0
|
"maximum": 20000,
|
||||||
|
"digits": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "NumberSpinner",
|
"type": "NumberSpinner",
|
||||||
"name": "FilterHits",
|
"name": "FilterHits",
|
||||||
"caption": "Filter Treffer bis Übernahme",
|
"caption": "Filter Treffer bis Übernahme",
|
||||||
"minimum": 1,
|
"minimum": 1,
|
||||||
"maximum": 10
|
"maximum": 10,
|
||||||
|
"digits": 0
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -219,4 +243,4 @@
|
|||||||
"onClick": "GEF_Update($id);"
|
"onClick": "GEF_Update($id);"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
+111
-1
@@ -18,6 +18,8 @@ class Bat_EV_SDL_V4 extends IPSModule
|
|||||||
$this->RegisterPropertyFloat("FilterTolerancePct", 15.0); // %
|
$this->RegisterPropertyFloat("FilterTolerancePct", 15.0); // %
|
||||||
$this->RegisterPropertyFloat("FilterRampWPerSec", 2000.0); // W/s
|
$this->RegisterPropertyFloat("FilterRampWPerSec", 2000.0); // W/s
|
||||||
$this->RegisterPropertyInteger("FilterHits", 1);
|
$this->RegisterPropertyInteger("FilterHits", 1);
|
||||||
|
$this->RegisterPropertyFloat("EV_Recalc_IntervalHours", 6.0);
|
||||||
|
$this->RegisterPropertyFloat("EV_Recalc_TolerancePct", 2.0);
|
||||||
|
|
||||||
// Status
|
// Status
|
||||||
$this->RegisterVariableBoolean("State", "Aktiv", "~Switch", 1);
|
$this->RegisterVariableBoolean("State", "Aktiv", "~Switch", 1);
|
||||||
@@ -424,7 +426,8 @@ class Bat_EV_SDL_V4 extends IPSModule
|
|||||||
|
|
||||||
$eSDL = ($sdlTotal > 0.0) ? $sdlTotal * $lastSdlPct / 100.0 : 0.0;
|
$eSDL = ($sdlTotal > 0.0) ? $sdlTotal * $lastSdlPct / 100.0 : 0.0;
|
||||||
$eEV = ($evTotal > 0.0) ? $evTotal * $lastEvPct / 100.0 : 0.0;
|
$eEV = ($evTotal > 0.0) ? $evTotal * $lastEvPct / 100.0 : 0.0;
|
||||||
|
|
||||||
|
$this->MaybeRecalculateEVFromPhysical($plan, $eSDL, $eEV, $sdlTotal, $evTotal);
|
||||||
$this->SetBuffer("Int_E_SDL_kWh", (string)$eSDL);
|
$this->SetBuffer("Int_E_SDL_kWh", (string)$eSDL);
|
||||||
$this->SetBuffer("Int_E_EV_kWh", (string)$eEV);
|
$this->SetBuffer("Int_E_EV_kWh", (string)$eEV);
|
||||||
$this->SetBuffer("Int_LastTs", (string)$now);
|
$this->SetBuffer("Int_LastTs", (string)$now);
|
||||||
@@ -916,6 +919,113 @@ class Bat_EV_SDL_V4 extends IPSModule
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function MaybeRecalculateEVFromPhysical(array $plan, float $eSDL, float &$eEV, float $sdlTotal, float $evTotal): void
|
||||||
|
{
|
||||||
|
if ($evTotal <= 0.0 || $sdlTotal <= 0.0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$intervalHours = max(0.0, (float)$this->ReadPropertyFloat("EV_Recalc_IntervalHours"));
|
||||||
|
|
||||||
|
if ($intervalHours <= 0.0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$now = microtime(true);
|
||||||
|
|
||||||
|
$lastCheckTs = (float)$this->GetBufferSafe("EV_Recalc_LastCheckTs");
|
||||||
|
|
||||||
|
// Nur alle X Stunden prüfen
|
||||||
|
if (
|
||||||
|
$lastCheckTs > 0.0 &&
|
||||||
|
($now - $lastCheckTs) < ($intervalHours * 3600.0)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->SetBuffer("EV_Recalc_LastCheckTs", (string)$now);
|
||||||
|
|
||||||
|
// SDL muss bei 50% sein
|
||||||
|
$sdlPct = ($eSDL / $sdlTotal) * 100.0;
|
||||||
|
|
||||||
|
if (abs($sdlPct - 50.0) > 0.001) {
|
||||||
|
$this->SendDebug(
|
||||||
|
"EV_Recalc",
|
||||||
|
"Skip: SDL nicht bei 50%, aktuell=" . round($sdlPct, 3) . "%",
|
||||||
|
0
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$newEVkWh = 0.0;
|
||||||
|
|
||||||
|
foreach (($plan["bats"] ?? []) as $bat) {
|
||||||
|
|
||||||
|
$capKWh = (float)($bat["capKWh"] ?? 0.0);
|
||||||
|
$socVarId = (int)($bat["socVarId"] ?? 0);
|
||||||
|
|
||||||
|
$realSocPct = $this->ReadSocPercent($socVarId);
|
||||||
|
$realKWh = $capKWh * $realSocPct / 100.0;
|
||||||
|
|
||||||
|
$underKWh = (float)($bat["underKWh"] ?? 0.0);
|
||||||
|
|
||||||
|
// Maximales EV Fenster dieser Batterie
|
||||||
|
$evBatTotal = (float)($bat["EV_kWh_total"] ?? 0.0);
|
||||||
|
|
||||||
|
// EV Anteil relativ zur unteren Grenze
|
||||||
|
$evPart = $realKWh - $underKWh;
|
||||||
|
|
||||||
|
// Begrenzung:
|
||||||
|
// unter underKWh => 0
|
||||||
|
// über upKWh => max EV Fenster
|
||||||
|
$evPart = max(0.0, min($evBatTotal, $evPart));
|
||||||
|
|
||||||
|
$newEVkWh += $evPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global begrenzen
|
||||||
|
$newEVkWh = max(0.0, min($evTotal, $newEVkWh));
|
||||||
|
|
||||||
|
$newEVpct = ($evTotal > 0.0)
|
||||||
|
? ($newEVkWh / $evTotal * 100.0)
|
||||||
|
: 0.0;
|
||||||
|
|
||||||
|
$oldEVpct = ($evTotal > 0.0)
|
||||||
|
? ($eEV / $evTotal * 100.0)
|
||||||
|
: 0.0;
|
||||||
|
|
||||||
|
$tolPct = max(0.0, (float)$this->ReadPropertyFloat("EV_Recalc_TolerancePct"));
|
||||||
|
|
||||||
|
// Nur übernehmen wenn Differenz gross genug
|
||||||
|
if (abs($newEVpct - $oldEVpct) <= $tolPct) {
|
||||||
|
|
||||||
|
$this->SendDebug(
|
||||||
|
"EV_Recalc",
|
||||||
|
"Skip: Differenz innerhalb Toleranz. Alt=" .
|
||||||
|
round($oldEVpct, 3) .
|
||||||
|
"% Neu=" .
|
||||||
|
round($newEVpct, 3) .
|
||||||
|
"%",
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$eEV = $newEVkWh;
|
||||||
|
|
||||||
|
$this->SendDebug(
|
||||||
|
"EV_Recalc",
|
||||||
|
"EV neu berechnet. Alt=" .
|
||||||
|
round($oldEVpct, 3) .
|
||||||
|
"% Neu=" .
|
||||||
|
round($newEVpct, 3) .
|
||||||
|
"%",
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private function RefreshDynamicPlanValues(array $plan): array
|
private function RefreshDynamicPlanValues(array $plan): array
|
||||||
{
|
{
|
||||||
foreach ($plan["bats"] as &$bat) {
|
foreach ($plan["bats"] as &$bat) {
|
||||||
|
|||||||
Reference in New Issue
Block a user