no message
This commit is contained in:
+64
-40
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"elements": [
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"type": "List",
|
||||
"name": "Batteries",
|
||||
@@ -95,17 +95,17 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"caption": "Min. SoC",
|
||||
"name": "minPhysicalSocPct",
|
||||
"width": "100px",
|
||||
"suffix": " %",
|
||||
"add": 5,
|
||||
"edit": {
|
||||
"caption": "Min. SoC",
|
||||
"name": "minPhysicalSocPct",
|
||||
"width": "100px",
|
||||
"suffix": " %",
|
||||
"add": 5,
|
||||
"edit": {
|
||||
"type": "NumberSpinner",
|
||||
"minimum": 0,
|
||||
"maximum": 30,
|
||||
"digits": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"values": []
|
||||
@@ -131,13 +131,13 @@
|
||||
"digits": 0
|
||||
},
|
||||
{
|
||||
"type": "NumberSpinner",
|
||||
"name": "ReserveHours",
|
||||
"caption": "SDL Reservezeit",
|
||||
"suffix": " h",
|
||||
"minimum": 0,
|
||||
"maximum": 24,
|
||||
"digits": 2
|
||||
"type": "NumberSpinner",
|
||||
"name": "ReserveHours",
|
||||
"caption": "SDL Reservezeit",
|
||||
"suffix": " h",
|
||||
"minimum": 0,
|
||||
"maximum": 24,
|
||||
"digits": 2
|
||||
},
|
||||
{
|
||||
"type": "NumberSpinner",
|
||||
@@ -167,42 +167,66 @@
|
||||
"type": "NumberSpinner",
|
||||
"name": "UpdateInterval",
|
||||
"caption": "Update Intervall",
|
||||
"suffix": "S",
|
||||
"suffix": " s",
|
||||
"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
|
||||
},
|
||||
|
||||
{
|
||||
"type": "CheckBox",
|
||||
"name": "FilterAktiv",
|
||||
"caption": "Filter für aktuelle EV/SDL Leistung aktiv. Dient für die Visualisierung, um Leistungssprünge zu vermeiden."
|
||||
},
|
||||
{
|
||||
"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"
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"type": "NumberSpinner",
|
||||
"name": "FilterTolerancePct",
|
||||
"caption": "Filter Toleranz (%)",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"digits": 1
|
||||
"type": "NumberSpinner",
|
||||
"name": "FilterTolerancePct",
|
||||
"caption": "Filter Toleranz",
|
||||
"suffix": " %",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"digits": 1
|
||||
},
|
||||
{
|
||||
"type": "NumberSpinner",
|
||||
"name": "FilterRampWPerSec",
|
||||
"caption": "Filter Rampe (W/s)",
|
||||
"minimum": 100,
|
||||
"maximum": 20000,
|
||||
"digits": 0
|
||||
"type": "NumberSpinner",
|
||||
"name": "FilterRampWPerSec",
|
||||
"caption": "Filter Rampe",
|
||||
"suffix": " W/s",
|
||||
"minimum": 100,
|
||||
"maximum": 20000,
|
||||
"digits": 0
|
||||
},
|
||||
{
|
||||
"type": "NumberSpinner",
|
||||
"name": "FilterHits",
|
||||
"caption": "Filter Treffer bis Übernahme",
|
||||
"minimum": 1,
|
||||
"maximum": 10
|
||||
"type": "NumberSpinner",
|
||||
"name": "FilterHits",
|
||||
"caption": "Filter Treffer bis Übernahme",
|
||||
"minimum": 1,
|
||||
"maximum": 10,
|
||||
"digits": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -219,4 +243,4 @@
|
||||
"onClick": "GEF_Update($id);"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+111
-1
@@ -18,6 +18,8 @@ class Bat_EV_SDL_V4 extends IPSModule
|
||||
$this->RegisterPropertyFloat("FilterTolerancePct", 15.0); // %
|
||||
$this->RegisterPropertyFloat("FilterRampWPerSec", 2000.0); // W/s
|
||||
$this->RegisterPropertyInteger("FilterHits", 1);
|
||||
$this->RegisterPropertyFloat("EV_Recalc_IntervalHours", 6.0);
|
||||
$this->RegisterPropertyFloat("EV_Recalc_TolerancePct", 2.0);
|
||||
|
||||
// Status
|
||||
$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;
|
||||
$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_EV_kWh", (string)$eEV);
|
||||
$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
|
||||
{
|
||||
foreach ($plan["bats"] as &$bat) {
|
||||
|
||||
Reference in New Issue
Block a user