/* * PLC program to hierarchically turn on/off multiple relays. * * Every few cycles (configurable, 1 cycle = 1 minute), another relay will be turned on as long as enough * excess energy is still available. The on/off thresholds (excess energy/Einspeisung) can be specified * for each relay output individually via automation web UI. * * The highest priority relay will be turned on first and turned off last. The priorities of the relays * are determined by the order in which they are configured in the automation web UI. * */ ", 3); $OnDelay = 3; // in automation cycles $OffDelay = 2; // in automation cycles //$Einspeisung = 3000; // for simulation purpose // determine used relays $Relays = Array(); $NrRelays = 2; $NrOutputs = 4; for($RelayNr = 1; $RelayNr <= $NrRelays; $RelayNr++) { if ($var["Relais".$RelayNr."aktiv"] == 0) // activated in UI? continue; for($OutputNr = 1; $OutputNr <= $NrOutputs; $OutputNr++) { if (!isset(${"Relais".$RelayNr."Kontakte"}[$OutputNr])) continue; $Relay = Array(); $Relay["Relay"] = $RelayNr; $Relay["Output"] = $OutputNr; $Relay["State"] = ${"Relais".$RelayNr."Kontakte"}[$OutputNr]; $Relay["SMon"] = $var["Relais".$RelayNr."K".$OutputNr."SMein"]; $Relay["SMoff"] = $var["Relais".$RelayNr."K".$OutputNr."SMaus"]; log_schreiben("adding relay ".$Relay["Relay"]."/".$Relay["Output"]." (state=".$Relay["State"]. ", SMon >=".$Relay["SMon"].", SMoff <".$Relay["SMoff"].")", "", 3); array_push($Relays, $Relay); // first we set the original state in order to disable Solaranzeige calculations $UserKontaktAuswertung["Relais".$Relay["Relay"]]["Kontakt".$Relay["Output"]] = $Relay["State"]; } } // hierarchically calculate new relay states $LastActivatedRelay = null; foreach ($Relays as $Relay) { if (!$Relay["State"]) { // turn on? $UserKontaktAuswertung["Relais".$Relay["Relay"]]["Kontakt".$Relay["Output"]] = calc_state($Relay, $Einspeisung, $OnDelay); break; } $LastActivatedRelay = $Relay; } if (!is_null($LastActivatedRelay)) { // turn off? $UserKontaktAuswertung["Relais".$LastActivatedRelay["Relay"]]["Kontakt".$LastActivatedRelay["Output"]] = calc_state($LastActivatedRelay, $Einspeisung, $OffDelay); } log_schreiben("--- auto-math.php ---", "ENDE", 3); // calculate relay state based on current feed and specified delay function calc_state($Relay, $Feed, $Delay) { $Cond = false; $State = $Relay["State"]; $Cnt = (int)file_get_contents("/tmp/cnt_".$Relay["Relay"]."_".$Relay["Output"]); log_schreiben("calculating state for relay ".$Relay["Relay"]."/".$Relay["Output"]. " (state=".$State.")", "", 3); // relay off -> turn on? if (!$State) { if ($Feed >= $Relay["SMon"]) { $Cnt++; $Cond = true; } else $Cnt = 0; // condition not met -> reset count } // relay on -> turn off? else { if ($Feed < $Relay["SMoff"]) { $Cnt++; $Cond = true; } else $Cnt = 0; // condition not met -> reset count } // hysteresis if ($Cond and $Cnt >= $Delay) { log_schreiben("changing state for relay ".$Relay["Relay"]."/".$Relay["Output"]. " from ".$State." to ".(int)!$State, "", 3); $State = (int)!$State; $Cnt = 0; // flip -> reset count } else { log_schreiben("no state change for relay ".$Relay["Relay"]."/".$Relay["Output"]. " (cnt=".$Cnt.", delay=".$Delay.", feed=".$Feed. ", threshold ".($State ? "<".$Relay["SMoff"] : ">=".$Relay["SMon"]).")", "", 3); } file_put_contents("/tmp/cnt_".$Relay["Relay"]."_".$Relay["Output"], $Cnt); return $State; } ?>