diff --git a/Bat_EV_SDL/module.php b/Bat_EV_SDL/module.php index b46352f..4a5e3cc 100644 --- a/Bat_EV_SDL/module.php +++ b/Bat_EV_SDL/module.php @@ -53,7 +53,7 @@ class Bat_EV_SDL extends IPSModule { if ($Ident === "State") { SetValue($this->GetIDForIdent("State"), (bool)$Value); - if ($Value) { + if ((bool)$Value) { $this->Update(); } return; @@ -78,7 +78,7 @@ class Bat_EV_SDL extends IPSModule } $sdlPowerW = max(0, (int)$this->ReadPropertyInteger("SDL_Leistung")); - $reserveH = 0.5; + $reserveH = 0.5; // 30 Minuten fix $eps = 0.0001; // Summe Max-Leistungen @@ -88,6 +88,8 @@ class Bat_EV_SDL extends IPSModule if ($p > 0) $sumBatPowerW += $p; } if ($sumBatPowerW <= 0) return; + + // SDL begrenzen if ($sdlPowerW > $sumBatPowerW) $sdlPowerW = $sumBatPowerW; // Summen Leistung @@ -98,14 +100,19 @@ class Bat_EV_SDL extends IPSModule $P_EV_laden = 0.0; $P_EV_entladen = 0.0; - // Fensterposition & EV-Füllstand - $sumPos = 0.0; $cntPos = 0; - $sumEV = 0.0; $sumEVcap = 0.0; + // EV-Fenster-Füllstand (systemweit gewichtet) + $sumEV = 0.0; + $sumEVcap = 0.0; + + // SDL Fensterposition (JETZT GEWICHTET nach Fenstergröße) + $sumPosWeighted = 0.0; + $sumPosWeight = 0.0; $calc = []; foreach ($batteries as $b) { + $typ = (string)($b["typ"] ?? ""); $pBat = (int)($b["powerbat"] ?? 0); $cap = (float)($b["capazity"] ?? 0); if ($pBat <= 0 || $cap <= 0) continue; @@ -114,15 +121,22 @@ class Bat_EV_SDL extends IPSModule $E = $cap * $socPct / 100.0; // SDL-Leistungsanteil - $pSDL = min(($sdlPowerW * $pBat) / $sumBatPowerW, $pBat); + $pSDL = min(($sdlPowerW * $pBat) / $sumBatPowerW, (float)$pBat); + if ($pSDL < 0) $pSDL = 0.0; + $pEV = max(0.0, $pBat - $pSDL); $P_SDL_max += $pSDL; $P_EV_max += $pEV; + // Reserveenergie für 30 min $Ereq = ($pSDL * $reserveH) / 1000.0; + + // Fenster $Emin = $Ereq; $Emax = $cap - $Ereq; + $range = $Emax - $Emin; // = cap - 2*Ereq + $EVcap = max(0.0, $range); // SDL möglich? if ($E >= $Emin) $P_SDL_entladen += $pSDL; @@ -132,34 +146,49 @@ class Bat_EV_SDL extends IPSModule if ($E > $Emin) $P_EV_entladen += $pEV; if ($E < $Emax) $P_EV_laden += $pEV; - // Fensterposition - $range = $Emax - $Emin; - if ($range > $eps) { - $pos = ($E - $Emin) / $range; - $pos = max(0.0, min(1.0, $pos)); - $sumPos += $pos * 100.0; - $cntPos++; + // EV Energie im Fenster (für SoC_EV) + $EV = 0.0; + if ($EVcap > $eps) { + $EV = max(0.0, min($E - $Emin, $EVcap)); + $sumEV += $EV; + $sumEVcap += $EVcap; } - // EV-Füllstand - $EVcap = max(0.0, $range); - $EV = max(0.0, min($E - $Emin, $EVcap)); - $sumEV += $EV; - $sumEVcap += $EVcap; + // SDL Fensterposition (0..100), GEWICHTET nach EVcap + if ($EVcap > $eps) { + $pos = ($E - $Emin) / $EVcap; // 0..1 + $pos = max(0.0, min(1.0, $pos)); + $posPct = $pos * 100.0; + + $sumPosWeighted += $posPct * $EVcap; + $sumPosWeight += $EVcap; + } else { + $posPct = 0.0; + } $calc[] = [ - "typ" => $b["typ"] ?? "", + "typ" => $typ, + "soc_pct" => round($socPct, 2), "E_kWh" => round($E, 3), - "Emin" => round($Emin, 3), - "Emax" => round($Emax, 3), + "pSDL_W" => round($pSDL, 0), - "pEV_W" => round($pEV, 0) + "pEV_W" => round($pEV, 0), + + "Ereq_kWh" => round($Ereq, 3), + "Emin_kWh" => round($Emin, 3), + "Emax_kWh" => round($Emax, 3), + "EVcap_kWh" => round($EVcap, 3), + + "SDL_pos_pct" => round($posPct, 2) ]; } - // Setzen Variablen - SetValue($this->GetIDForIdent("SDL_Pos"), $cntPos ? round($sumPos / $cntPos, 2) : 0.0); - SetValue($this->GetIDForIdent("SoC_EV"), $sumEVcap > $eps ? round(($sumEV / $sumEVcap) * 100.0, 2) : 0.0); + // Ergebnisse + $SDL_Pos = ($sumPosWeight > $eps) ? ($sumPosWeighted / $sumPosWeight) : 0.0; + $SoC_EV = ($sumEVcap > $eps) ? (($sumEV / $sumEVcap) * 100.0) : 0.0; + + SetValue($this->GetIDForIdent("SDL_Pos"), round($SDL_Pos, 2)); + SetValue($this->GetIDForIdent("SoC_EV"), round($SoC_EV, 2)); SetValue($this->GetIDForIdent("P_SDL_max"), round($P_SDL_max, 0)); SetValue($this->GetIDForIdent("P_SDL_laden"), round($P_SDL_laden, 0)); @@ -172,13 +201,19 @@ class Bat_EV_SDL extends IPSModule SetValue($this->GetIDForIdent("CalcJSON"), json_encode($calc, JSON_PRETTY_PRINT)); } + /** + * SoC in Prozent (0..100). Akzeptiert 0..1 als 0..100. + */ private function ReadSocPercent(int $varId): float { if ($varId <= 0 || !IPS_VariableExists($varId)) return 0.0; + $v = GetValue($varId); if (!is_numeric($v)) return 0.0; + $f = (float)$v; - if ($f >= 0 && $f <= 1) $f *= 100.0; + if ($f >= 0.0 && $f <= 1.0) $f *= 100.0; + return max(0.0, min(100.0, $f)); } }