RegisterPropertyInteger("Peakleistung", 0); $this->RegisterPropertyInteger("Ueberschussleistung", 0); $this->RegisterPropertyInteger("Netzbezug", 0); // Initialisierung mit 0 $this->RegisterPropertyString("EnergyUserList", "[]"); // Timer registrieren $this->RegisterTimer("Timer_DistributeEnergy",5000,"IPS_RequestAction(" .$this->InstanceID .', "DistributeEnergy", "");'); } public function ApplyChanges() { parent::ApplyChanges(); //Liste aller Verbraucher einlesen $energyUserList = $this->ReadPropertyString("EnergyUserList"); } public function RequestAction($Ident, $Value) { switch ($Ident) { case "DistributeEnergy": $this->DistributeEnergy(); break; case "ApplyChanges": $this->ApplyChanges(); break; default: throw new Exception("Invalid Ident"); } } public function DistributeEnergy() { // Systemvariablen abrufen $Netzbezug = GetValue($this->ReadPropertyInteger("Netzbezug")); $Peakleistung = $this->ReadPropertyInteger("Peakleistung"); $Ueberschussleistung = $this->ReadPropertyInteger("Ueberschussleistung"); // Fallunterscheidung ob auf Solarladen oder Peakshaving gerregelt wird. if ($Netzbezug < ($Peakleistung - $Ueberschussleistung) / 2) { $remainingPower = -1 * (-1 * $Ueberschussleistung + $Netzbezug); $Is_Peak_Shaving = false; } else { $remainingPower = $Peakleistung - $Netzbezug; $Is_Peak_Shaving = true; } // Alle Energieverbraucher auslesen und dekodieren $energyUserList = json_decode($this->ReadPropertyString("EnergyUserList"), true); if (empty($energyUserList)) { // Liste ist leer, daher nichts zu tun return; } // Frage alle Energieverbraucher ab, was sie für Leistungen benötigen könnten foreach ($energyUserList as $user) { if (IPS_InstanceExists($user["EnergyUser"])) { IPS_RequestAction($user["EnergyUser"],"GetCurrentData",$Is_Peak_Shaving); } } $filteredEnergyUsers = []; // Array das später mit allen Verbrauchsdaten der Energieverbraucher gefüllt wird $allIdle = true; // Variable zur Überprüfung, ob alle Benutzer Idle = true sind $totalCurrentPower = 0; // Variable zur Summierung der CurrentPower Werte // Fülle das Array mit allen entsprechenden Werten der Verbraucher ab foreach ($energyUserList as $user) { if (!IPS_InstanceExists($user["EnergyUser"])) { continue; } // Werte direkt von der EnergyUser-Instanz abrufen $currentPower = GetValue(IPS_GetObjectIDByIdent("CurrentPower", $user["EnergyUser"])); $usedEnergy = GetValue(IPS_GetObjectIDByIdent("UsedEnergy", $user["EnergyUser"])); $userPrio = GetValue(IPS_GetObjectIDByIdent("UserPrio", $user["EnergyUser"])); $lockPrio = GetValue(IPS_GetObjectIDByIdent("LockPrio", $user["EnergyUser"])); $idle = GetValue(IPS_GetObjectIDByIdent("Idle", $user["EnergyUser"])); $powerStepsJson = GetValue(IPS_GetObjectIDByIdent("PowerSteps", $user["EnergyUser"])); $powerSteps = json_decode($powerStepsJson, true); // EnergyUser-Daten zum gefilterten Array hinzufügen $filteredEnergyUsers[] = [ "EnergyUser" => $user["EnergyUser"], "InstanceID" => $user["EnergyUser"], "CurrentPower" => $currentPower, "UsedEnergy" => $usedEnergy, "UserPrio" => $userPrio, "LockPrio" => $lockPrio, "Idle" => $idle, "PowerSteps" => $powerSteps, ]; // Überprüfen, ob alle Benutzer Idle = true sind, wenn einer nicht ist, wird später verworfen... if (!$idle) { $allIdle = false; } // Addiere die aktuell bereits verwendete Leistung auf, um sie bei der verteilung zu berücksichtigen $totalCurrentPower += $currentPower; } // Berücksichtigung der bereits verteilten Leistungen (nachher kann dafür wieder bei 0 begonnen werden zu verteilen) $remainingPower += $totalCurrentPower; // Abbrechen wenn es keine gefilterten User gibt if (empty($filteredEnergyUsers)) { return; } // Wenn nicht alle Benutzer Idle = true sind, rufe SetCurrentPower mit CurrentPower Werten auf, (alle Verbraucher behalten die aktuelle Leistung) if (!$allIdle) { foreach ($filteredEnergyUsers as $user) { IPS_RequestAction($user["InstanceID"],"SetCurrentPower",$user["CurrentPower"]); } return; } // Sortiere die Verbruacher nach Priorität entweder der PV_Prio oder der Peak Prio usort($filteredEnergyUsers, function ($a, $b) use ( $Is_Peak_Shaving ) { $primaryKey = $Is_Peak_Shaving ? "LockPrio" : "UserPrio"; // Wenn die Prio geleich ist, sortiere danach welcher verbraucher bisher am wenigsten Energie bekommen hat. if ($a[$primaryKey] == $b[$primaryKey]) { return $a["UsedEnergy"] <=> $b["UsedEnergy"]; } return $a[$primaryKey] <=> $b[$primaryKey]; }); // Primärschlüssel für die Priorität basierend auf dem Parameter auswählen (für sortierung in gruppen anschliessend) $priorityKey = $Is_Peak_Shaving ? "LockPrio" : "UserPrio"; // Schleife durch alle Prioritäten $priorities = array_unique( array_column($filteredEnergyUsers, $priorityKey) ); $groupedUsers = []; foreach ($priorities as $priority) { $groupedUsers[$priority] = array_filter( $filteredEnergyUsers, function ($user) use ($priority, $priorityKey) { return $user[$priorityKey] == $priority; } ); } // Jetzt werden die energien pro gruppe verteilt (Immer alle pro prio in einer gruppe miteinander) foreach ($groupedUsers as $priority => $users) { // EnergyUser mit gleicher Priorität sammeln $samePriorityUsers = isset($groupedUsers[$priority]) ? $groupedUsers[$priority] : []; // Wenn keine EnergyUser mit gleicher Priorität vorhanden sind, überspringen if (empty($samePriorityUsers)) { continue; } $withZero = []; $withoutZero = []; // Verbraucher die nicht 0 Annhemen können, bekommen einfach den tiefsten wert foreach ($samePriorityUsers as $entry) { if (in_array(0, $entry["PowerSteps"])) { $withZero[] = $entry; } else { $withoutZero[] = $entry; } } // Verbraucher die nicht 0 annhemen können erhalten nun den minimalwert if (!empty($withoutZero)) { foreach ($withoutZero as $entry) { $instanceID = $entry["InstanceID"]; $minPowerStep = min($entry["PowerSteps"]); IPS_RequestAction($instanceID,"SetCurrentPower",$minPowerStep ); $remainingPower -= $entry["CurrentPower"]; } } // Nun die verteilen, die 0 erhalten können. $samePriorityUsers = $withZero; // Array für die verteilte Energie pro User erstellen $userEnergyProv = []; $userEnergyProv = array_fill_keys(array_column($samePriorityUsers, "InstanceID"), 0); // Initialisierung für jeden Benutzer auf 0 setzen // Alle Schritte der Benutzer in einem Array sammeln $allSteps = []; foreach ($samePriorityUsers as $user) { foreach ($user["PowerSteps"] as $step) { $allSteps[] = [ "user" => $user["InstanceID"], "step" => $step, ]; } } // Sortiere die Schritte nach Größe usort($allSteps, function ($a, $b) { return $a["step"] <=> $b["step"]; }); // Iteriere durch alle Schritte foreach ($allSteps as $entry) { $user = $entry["user"]; $powerstep = $entry["step"]; // Überprüfe, ob noch genügend verbleibende Energie für den nächsten Schritt vorhanden ist if ($remainingPower >= $powerstep - $userEnergyProv[$user]) { // Aktualisiere die verbleibende Energie und die bereitgestellte Energie für den Benutzer $remainingPower -= $powerstep - $userEnergyProv[$user]; $userEnergyProv[$user] = $powerstep; } } // Prüfen, dass jeder User mindestens seinen minimalwert an Leistung bekommt foreach ($userEnergyProv as $userInstanceID => $leistung) { $minimalleitsung = min( array_column( array_filter($allSteps, function ($entry) use ( $userInstanceID ) { return $entry["user"] == $userInstanceID; }), "step" ) ); // Jedem user den höheren der beiden werte aus minimalwert oder vergebenem zuteilen $leistung = max($leistung, $minimalleitsung); // Methode SetCurrentPower für jeden EnergyUser mit der entsprechenden Energie aufrufen if (IPS_InstanceExists($userInstanceID)) { IPS_RequestAction($userInstanceID,"SetCurrentPower",$leistung); } } } } } ?>