no message
This commit is contained in:
+164
-175
@@ -490,197 +490,186 @@ class Bat_EV_SDL_V2 extends IPSModule
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private function CalculateBatteryDistribution(float $pEvW, float $pSdlW): array
|
private function CalculateBatteryDistribution(float $pEvW, float $pSdlW): array
|
||||||
{
|
{
|
||||||
$calcJsonId = $this->GetIDForIdent("CalcJSON");
|
$calcJsonId = $this->GetIDForIdent("CalcJSON");
|
||||||
// Fallback, falls Variable leer ist oder nicht existiert
|
// Fallback, falls Variable leer ist oder nicht existiert
|
||||||
if (!IPS_VariableExists($calcJsonId)) {
|
if (!IPS_VariableExists($calcJsonId)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
$rawJson = (string)GetValue($calcJsonId);
|
$rawJson = (string)GetValue($calcJsonId);
|
||||||
if (empty($rawJson)) {
|
if (empty($rawJson)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
$calc = json_decode($rawJson, true);
|
$calc = json_decode($rawJson, true);
|
||||||
$batteries = $calc['batteries'] ?? [];
|
$batteries = $calc['batteries'] ?? [];
|
||||||
|
|
||||||
// ---------------------------------------------------------
|
|
||||||
// Hilfsfunktion: Verteilungslogik (Closure)
|
|
||||||
// ---------------------------------------------------------
|
|
||||||
$distributePower = function(float $targetPower, string $mode) use ($batteries): array {
|
|
||||||
// Initialisierung des Ergebnis-Arrays (Key = idx, Value = zugewiesene Watt)
|
|
||||||
$result = [];
|
|
||||||
foreach ($batteries as $bat) {
|
|
||||||
$result[$bat['idx']] = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (abs($targetPower) < 0.01) {
|
|
||||||
return $result; // Nichts zu tun
|
|
||||||
}
|
|
||||||
|
|
||||||
$isCharge = ($targetPower > 0);
|
|
||||||
$absPower = abs($targetPower);
|
|
||||||
// Relevante Keys basierend auf Modus (EV oder SDL) und Richtung (Laden/Entladen)
|
|
||||||
$socKey = ($mode === 'EV') ? 'EV_SOC' : 'SDL_SOC';
|
|
||||||
// Achtung: JSON Limits sind in kW, wir rechnen in Watt -> * 1000
|
|
||||||
$limitKey = $isCharge ? $mode . '_Charge_kW' : $mode . '_Discharge_kW';
|
|
||||||
|
|
||||||
// 1. Batterien vorbereiten und gruppieren nach gerundetem SoC
|
|
||||||
$groups = [];
|
|
||||||
foreach ($batteries as $bat) {
|
|
||||||
$soc = (int)round($bat[$socKey]); // Auf ganze Zahl runden
|
|
||||||
$maxW = ((float)$bat[$limitKey]) * 1000.0; // kW in Watt umrechnen
|
|
||||||
$groups[$soc][] = [
|
|
||||||
'idx' => $bat['idx'],
|
|
||||||
'maxW' => $maxW
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Sortieren der Gruppen
|
|
||||||
// Laden: Wenig SoC zuerst (ASC) -> leere füllen
|
|
||||||
// Entladen: Viel SoC zuerst (DESC) -> volle leeren
|
|
||||||
if ($isCharge) {
|
|
||||||
ksort($groups);
|
|
||||||
} else {
|
|
||||||
krsort($groups);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Verteilung
|
|
||||||
$remainingNeeded = $absPower;
|
|
||||||
|
|
||||||
foreach ($groups as $soc => $groupBatteries) {
|
|
||||||
if ($remainingNeeded <= 0.01) break;
|
|
||||||
|
|
||||||
// Gesamte verfügbare Leistung in dieser SoC-Gruppe ermitteln
|
|
||||||
$groupTotalCapacity = 0.0;
|
|
||||||
foreach ($groupBatteries as $gb) {
|
|
||||||
$groupTotalCapacity += $gb['maxW'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wie viel können wir dieser Gruppe zuteilen?
|
|
||||||
// Entweder alles was die Gruppe kann, oder den Restbedarf
|
|
||||||
$powerForThisGroup = min($remainingNeeded, $groupTotalCapacity);
|
|
||||||
|
|
||||||
// Proportionale Aufteilung innerhalb der Gruppe
|
|
||||||
// Falls Gruppe Kapazität 0 hat (Defekt/Voll), verhindern wir DivByZero
|
|
||||||
if ($groupTotalCapacity > 0) {
|
|
||||||
$ratio = $powerForThisGroup / $groupTotalCapacity;
|
|
||||||
foreach ($groupBatteries as $gb) {
|
|
||||||
$assigned = $gb['maxW'] * $ratio;
|
|
||||||
$result[$gb['idx']] = $assigned;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$remainingNeeded -= $powerForThisGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wenn wir entladen, müssen die Werte negativ sein
|
|
||||||
if (!$isCharge) {
|
|
||||||
foreach ($result as $idx => $val) {
|
|
||||||
$result[$idx] = -$val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
};
|
|
||||||
|
|
||||||
// ---------------------------------------------------------
|
|
||||||
// Hauptablauf
|
|
||||||
// ---------------------------------------------------------
|
|
||||||
|
|
||||||
// 1. Berechnung für EV und SDL getrennt durchführen
|
|
||||||
$evDistribution = $distributePower($pEvW, 'EV');
|
|
||||||
$sdlDistribution = $distributePower($pSdlW, 'SDL');
|
|
||||||
|
|
||||||
// 2. Ergebnisse zusammenführen und Output formatieren
|
|
||||||
$finalOutput = [];
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
// Hilfsfunktion: Verteilungslogik (Closure)
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
$distributePower = function(float $targetPower, string $mode) use ($batteries): array {
|
||||||
|
// Initialisierung des Ergebnis-Arrays (Key = idx, Value = zugewiesene Watt)
|
||||||
|
$result = [];
|
||||||
foreach ($batteries as $bat) {
|
foreach ($batteries as $bat) {
|
||||||
$idx = $bat['idx'];
|
$result[$bat['idx']] = 0.0;
|
||||||
// Summe der beiden Anforderungen (kann sich gegenseitig aufheben)
|
}
|
||||||
$valEv = $evDistribution[$idx] ?? 0.0;
|
|
||||||
$valSdl = $sdlDistribution[$idx] ?? 0.0;
|
|
||||||
$totalW = $valEv + $valSdl;
|
|
||||||
|
|
||||||
// Aufteilen in Charge / Discharge für das Return-Format
|
if (abs($targetPower) < 0.01) {
|
||||||
$chargeW = 0.0;
|
return $result; // Nichts zu tun
|
||||||
$dischargeW = 0.0;
|
}
|
||||||
|
|
||||||
if ($totalW > 0) {
|
$isCharge = ($targetPower > 0);
|
||||||
$chargeW = abs($totalW);
|
$absPower = abs($targetPower);
|
||||||
} else {
|
// Relevante Keys basierend auf Modus (EV oder SDL) und Richtung (Laden/Entladen)
|
||||||
$dischargeW = abs($totalW);
|
$socKey = ($mode === 'EV') ? 'EV_SOC' : 'SDL_SOC';
|
||||||
}
|
// Achtung: JSON Limits sind in kW, wir rechnen in Watt -> * 1000
|
||||||
|
$limitKey = $isCharge ? $mode . '_Charge_kW' : $mode . '_Discharge_kW';
|
||||||
|
|
||||||
// JSON Objekt erstellen
|
// 1. Batterien vorbereiten und gruppieren nach gerundetem SoC
|
||||||
$finalOutput[] = [
|
$groups = [];
|
||||||
"idx" => $idx,
|
foreach ($batteries as $bat) {
|
||||||
"typ" => (string)$bat['typ'], // Typ als String beibehalten
|
$soc = (int)round($bat[$socKey]); // Auf ganze Zahl runden
|
||||||
"chargeW" => round($chargeW, 0), // Optional: runden für sauberes JSON
|
$maxW = ((float)$bat[$limitKey]) * 1000.0; // kW in Watt umrechnen
|
||||||
"dischargeW" => round($dischargeW, 0)
|
$groups[$soc][] = [
|
||||||
|
'idx' => $bat['idx'],
|
||||||
|
'maxW' => $maxW
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. Sortieren der Gruppen
|
||||||
$batteriesRaw = json_decode($this->ReadPropertyString("Batteries"));
|
// Laden: Wenig SoC zuerst (ASC) -> leere füllen
|
||||||
|
// Entladen: Viel SoC zuerst (DESC) -> volle leeren
|
||||||
$totalPower_ist = 0;
|
if ($isCharge) {
|
||||||
|
ksort($groups);
|
||||||
foreach ($batteriesRaw as $bat) {
|
|
||||||
|
|
||||||
$totalPower_ist += GetValue($bat->register_bat_power);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$sumReq = (abs($pEvW) + abs($pSdlW));
|
|
||||||
$sumReqRel = ($pEvW + $pSdlW);
|
|
||||||
|
|
||||||
if($sumReq==0){
|
|
||||||
|
|
||||||
$this->SetValue("Aktuelle_Leistung_EV", $totalPower_ist / 2);
|
|
||||||
$this->SetValue("Aktuelle_Leistung_SDL", $totalPower_ist / 2);
|
|
||||||
|
|
||||||
}else{
|
|
||||||
|
|
||||||
if($pEvW>=0){
|
|
||||||
|
|
||||||
$this->SetValue("Aktuelle_Leistung_EV",((1+($totalPower_ist-$sumReqRel) / $sumReq)) * $pEvW);
|
|
||||||
|
|
||||||
}else{
|
|
||||||
$this->SetValue("Aktuelle_Leistung_EV",((1-($totalPower_ist-$sumReqRel) / $sumReq)) * $pEvW);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if($pSdlW>=0){
|
|
||||||
$this->SetValue("Aktuelle_Leistung_SDL",((1+($totalPower_ist-$sumReqRel) / $sumReq)) * $pSdlW);
|
|
||||||
|
|
||||||
}else{
|
|
||||||
$this->SetValue("Aktuelle_Leistung_SDL",((1-($totalPower_ist-$sumReqRel) / $sumReq)) * $pSdlW);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
$sumReq = (float)($pEvW + $pSdlW);
|
|
||||||
|
|
||||||
if (!is_finite($sumReq) || abs($sumReq) < 0.01) {
|
|
||||||
|
|
||||||
$this->SetValue("Aktuelle_Leistung_EV", $totalPower_ist / 2);
|
|
||||||
$this->SetValue("Aktuelle_Leistung_SDL", $totalPower_ist / 2);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
krsort($groups);
|
||||||
$this->SetValue("Aktuelle_Leistung_EV",($totalPower_ist / $sumReq) * $pEvW);
|
|
||||||
|
|
||||||
$this->SetValue("Aktuelle_Leistung_SDL",($totalPower_ist / $sumReq) * $pSdlW);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
// 3. Verteilung
|
||||||
|
$remainingNeeded = $absPower;
|
||||||
|
|
||||||
|
foreach ($groups as $soc => $groupBatteries) {
|
||||||
|
if ($remainingNeeded <= 0.01) break;
|
||||||
|
|
||||||
return $finalOutput;
|
// Gesamte verfügbare Leistung in dieser SoC-Gruppe ermitteln
|
||||||
|
$groupTotalCapacity = 0.0;
|
||||||
|
foreach ($groupBatteries as $gb) {
|
||||||
|
$groupTotalCapacity += $gb['maxW'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wie viel können wir dieser Gruppe zuteilen?
|
||||||
|
// Entweder alles was die Gruppe kann, oder den Restbedarf
|
||||||
|
$powerForThisGroup = min($remainingNeeded, $groupTotalCapacity);
|
||||||
|
|
||||||
|
// Proportionale Aufteilung innerhalb der Gruppe
|
||||||
|
// Falls Gruppe Kapazität 0 hat (Defekt/Voll), verhindern wir DivByZero
|
||||||
|
if ($groupTotalCapacity > 0) {
|
||||||
|
$ratio = $powerForThisGroup / $groupTotalCapacity;
|
||||||
|
foreach ($groupBatteries as $gb) {
|
||||||
|
$assigned = $gb['maxW'] * $ratio;
|
||||||
|
$result[$gb['idx']] = $assigned;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$remainingNeeded -= $powerForThisGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wenn wir entladen, müssen die Werte negativ sein
|
||||||
|
if (!$isCharge) {
|
||||||
|
foreach ($result as $idx => $val) {
|
||||||
|
$result[$idx] = -$val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
// Hauptablauf
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
|
||||||
|
// 1. Berechnung für EV und SDL getrennt durchführen
|
||||||
|
$evDistribution = $distributePower($pEvW, 'EV');
|
||||||
|
$sdlDistribution = $distributePower($pSdlW, 'SDL');
|
||||||
|
|
||||||
|
// 2. Ergebnisse zusammenführen und Output formatieren
|
||||||
|
$finalOutput = [];
|
||||||
|
|
||||||
|
foreach ($batteries as $bat) {
|
||||||
|
$idx = $bat['idx'];
|
||||||
|
// Summe der beiden Anforderungen (kann sich gegenseitig aufheben)
|
||||||
|
$valEv = $evDistribution[$idx] ?? 0.0;
|
||||||
|
$valSdl = $sdlDistribution[$idx] ?? 0.0;
|
||||||
|
$totalW = $valEv + $valSdl;
|
||||||
|
|
||||||
|
// Aufteilen in Charge / Discharge für das Return-Format
|
||||||
|
$chargeW = 0.0;
|
||||||
|
$dischargeW = 0.0;
|
||||||
|
|
||||||
|
if ($totalW > 0) {
|
||||||
|
$chargeW = abs($totalW);
|
||||||
|
} else {
|
||||||
|
$dischargeW = abs($totalW);
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSON Objekt erstellen
|
||||||
|
$finalOutput[] = [
|
||||||
|
"idx" => $idx,
|
||||||
|
"typ" => (string)$bat['typ'], // Typ als String beibehalten
|
||||||
|
"chargeW" => round($chargeW, 0), // Optional: runden für sauberes JSON
|
||||||
|
"dischargeW" => round($dischargeW, 0)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$batteriesRaw = json_decode($this->ReadPropertyString("Batteries"));
|
||||||
|
|
||||||
|
$totalPower_ist = 0;
|
||||||
|
|
||||||
|
foreach ($batteriesRaw as $bat) {
|
||||||
|
$totalPower_ist += GetValue($bat->register_bat_power);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------
|
||||||
|
// ALT (nicht mehr gebraucht) -> AUSKOMMENTIERT
|
||||||
|
// ----------------------------
|
||||||
|
/*
|
||||||
|
$sumReq = (abs($pEvW) + abs($pSdlW));
|
||||||
|
$sumReqRel = ($pEvW + $pSdlW);
|
||||||
|
|
||||||
|
if($sumReq==0){
|
||||||
|
|
||||||
|
$this->SetValue("Aktuelle_Leistung_EV", $totalPower_ist / 2);
|
||||||
|
$this->SetValue("Aktuelle_Leistung_SDL", $totalPower_ist / 2);
|
||||||
|
|
||||||
|
}else{
|
||||||
|
|
||||||
|
if($pEvW>=0){
|
||||||
|
$this->SetValue("Aktuelle_Leistung_EV",((1+($totalPower_ist-$sumReqRel) / $sumReq)) * $pEvW);
|
||||||
|
}else{
|
||||||
|
$this->SetValue("Aktuelle_Leistung_EV",((1-($totalPower_ist-$sumReqRel) / $sumReq)) * $pEvW);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($pSdlW>=0){
|
||||||
|
$this->SetValue("Aktuelle_Leistung_SDL",((1+($totalPower_ist-$sumReqRel) / $sumReq)) * $pSdlW);
|
||||||
|
}else{
|
||||||
|
$this->SetValue("Aktuelle_Leistung_SDL",((1-($totalPower_ist-$sumReqRel) / $sumReq)) * $pSdlW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ----------------------------
|
||||||
|
// NEU (genau deine gewünschte Logik)
|
||||||
|
// aktuelle - EV_SOLL = aktuelle SDL
|
||||||
|
// aktuelle - SDL_SOLL = aktuelle EV
|
||||||
|
// ----------------------------
|
||||||
|
$this->SetValue("Aktuelle_Leistung_SDL", $totalPower_ist - $pEvW);
|
||||||
|
$this->SetValue("Aktuelle_Leistung_EV", $totalPower_ist - $pSdlW);
|
||||||
|
|
||||||
|
return $finalOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private function WriteBatteryPowerSetpoints(array $distribution): void
|
private function WriteBatteryPowerSetpoints(array $distribution): void
|
||||||
{
|
{
|
||||||
IPS_LogMessage(
|
IPS_LogMessage(
|
||||||
|
|||||||
Reference in New Issue
Block a user