public void Prime(ZACommons commons, EventDriver eventDriver) { var relayBatteries = commons.GetBlockGroupWithName(BATTERY_GROUP); if (relayBatteries == null) { throw new Exception("Missing group: " + BATTERY_GROUP); } var relaySystems = commons.GetBlockGroupWithName(SYSTEMS_GROUP); if (relaySystems == null) { throw new Exception("Missing group: " + SYSTEMS_GROUP); } // Wake up batteries var batteries = ZACommons.GetBlocksOfType <IMyBatteryBlock>(relayBatteries.Blocks); ZACommons.EnableBlocks(batteries, true); ZACommons.SetBatteryRecharge(batteries, false); // And activate flight systems ZACommons.EnableBlocks(relaySystems.Blocks, true); eventDriver.Schedule(1.0, Release); }
private void RechargeOneBattery(List <IMyBatteryBlock> batteries) { for (var e = batteries.GetEnumerator(); e.MoveNext();) { var battery = e.Current; if (!battery.Enabled || battery.ProductionEnabled /* huh?! */) { if (!battery.Enabled) { battery.GetActionWithName("OnOff_On").Apply(battery); } ZACommons.SetBatteryRecharge(battery, true); return; } } }
private void DisableOneBattery(List <IMyBatteryBlock> batteries, PowerDetails totalDetails) { for (var e = batteries.GetEnumerator(); e.MoveNext();) { var battery = e.Current; if (battery.Enabled && battery.ProductionEnabled) { // But only if we can actually spare it var wouldBeOutput = totalDetails.CurrentPowerOutput - battery.CurrentPowerOutput; var wouldBeLoad = wouldBeOutput / (totalDetails.MaxPowerOutput - battery.MaxPowerOutput); if (wouldBeLoad <= POWER_MANAGER_HIGH_LOAD_THRESHOLD) { battery.GetActionWithName("OnOff_Off").Apply(battery); ZACommons.SetBatteryRecharge(battery, true); } return; } } }
public void HandleCommand(ZACommons commons, string argument) { argument = argument.Trim().ToLower(); if (argument == "forcerecharge") { var batteries = GetBatteries(commons); CurrentState = STATE_DISABLED; ZACommons.SetBatteryRecharge(batteries, true); return; } else if (argument == "pause") { CurrentState = null; Active = false; } else if (argument == "resume") { CurrentState = null; Active = true; } }
public void Run(ZACommons commons) { var batteries = GetBatteries(commons); if (CurrentState == null) { // First time run, get to known state and return CurrentState = STATE_NORMAL; SinceLastStateChange = TimeSpan.FromSeconds(0); ZACommons.SetBatteryRecharge(batteries, false); return; } SinceLastStateChange += commons.Program.ElapsedTime; var aggregateDetails = new AggregateBatteryDetails(batteries); string stateStr = "Unknown"; switch (CurrentState) { case STATE_NORMAL: if (SinceLastStateChange >= DischargeInterval) { // Don't check again until next interval, regardless of whether we // change state SinceLastStateChange = TimeSpan.FromSeconds(0); // Only recharge if there is available power, e.g. the batteries have no load, // and there is need to if (aggregateDetails.CurrentPowerOutput == 0.0f && aggregateDetails.CurrentStoredPower < aggregateDetails.MaxStoredPower && Active) { CurrentState = STATE_RECHARGE; ZACommons.SetBatteryRecharge(batteries, true); } else { // Force discharge, just in case ZACommons.SetBatteryRecharge(batteries, false); } } stateStr = Active ? "Normal" : "Paused"; break; case STATE_RECHARGE: // Too bad we don't have access to battery input (w/o parsing DetailInfo) // Then we could figure out non-battery load and cancel recharge pre-emptively // when needed if (SinceLastStateChange >= RechargeInterval) { CurrentState = STATE_NORMAL; SinceLastStateChange = TimeSpan.FromSeconds(0); ZACommons.SetBatteryRecharge(batteries, false); } stateStr = "Recharging"; break; case STATE_DISABLED: // Switch back to auto if full if (aggregateDetails.CurrentStoredPower >= aggregateDetails.MaxStoredPower) { CurrentState = STATE_NORMAL; SinceLastStateChange = TimeSpan.FromSeconds(0); ZACommons.SetBatteryRecharge(batteries, false); } stateStr = "Disabled"; break; } // See if we have a net power loss var newDraining = AddDrainData(aggregateDetails.CurrentPowerOutput > 0.0f); if (powerDrainHandler != null) { if (!Draining && newDraining) { powerDrainHandler.PowerDrainStarted(commons); } else if (Draining && !newDraining) { powerDrainHandler.PowerDrainEnded(commons); } } Draining = newDraining; commons.Echo(string.Format("Battery Manager: {0}", stateStr)); commons.Echo(string.Format("Total Stored Power: {0}h", ZACommons.FormatPower(aggregateDetails.CurrentStoredPower))); commons.Echo(string.Format("Max Stored Power: {0}h", ZACommons.FormatPower(aggregateDetails.MaxStoredPower))); if (Draining) { commons.Echo("Net power loss!"); } }
public void Run(ZACommons commons) { // Only care about power producers on this ship var producers = ZACommons.GetBlocksOfType <IMyTerminalBlock>(commons.Blocks, block => block is IMyPowerProducer); // Limit to functional batteries var batteries = ZACommons.GetBlocksOfType <IMyBatteryBlock>(producers, battery => battery.IsFunctional); if (batteries.Count == 0) { return; // Nothing to do if no batteries to manage } // All other power producers var otherProducers = ZACommons.GetBlocksOfType <IMyTerminalBlock>(producers, block => !(block is IMyBatteryBlock)); var batteryDetails = GetPowerDetails <IMyBatteryBlock>(batteries); var otherDetails = GetPowerDetails <IMyTerminalBlock>(otherProducers); var totalDetails = batteryDetails + otherDetails; //commons.Echo("Battery Load: " + batteryDetails.ToString()); //commons.Echo("Other Load: " + otherDetails.ToString()); //commons.Echo("Total Load: " + totalDetails.ToString()); // First, the degenerate cases... if (totalDetails.MaxPowerOutput == 0.0f) { return; // Don't think this is possible... } if (otherDetails.MaxPowerOutput == 0.0f) { // Nothing but our batteries. Just put all batteries online. ZACommons.EnableBlocks(batteries, true); ZACommons.SetBatteryRecharge(batteries, false); return; } var totalLoad = totalDetails.CurrentPowerOutput / totalDetails.MaxPowerOutput; // If total system load exceeds threshold, attempt to bring a battery online. if (totalLoad > POWER_MANAGER_HIGH_LOAD_THRESHOLD) { QuietTimer = TimeSpan.FromSeconds(0); // Sort by stored power descending batteries.Sort(batteryComparerDesc); // Bring the first recharging battery online, shut down all other recharging batteries // (just shutting them down would probably free up a lot of power... need // separate case?) var found = false; for (var e = batteries.GetEnumerator(); e.MoveNext();) { var battery = e.Current; if (battery.Enabled && battery.ProductionEnabled) { continue; // Battery is already online, don't touch it } if (!found) { // Found the first one, bring it online if (!battery.Enabled) { battery.GetActionWithName("OnOff_On").Apply(battery); } ZACommons.SetBatteryRecharge(battery, false); found = true; } else { // Shut it down if (battery.Enabled) { battery.GetActionWithName("OnOff_Off").Apply(battery); } } } } else if (totalLoad < POWER_MANAGER_LOW_LOAD_THRESHOLD) { QuietTimer += commons.Program.ElapsedTime; if (QuietTimer >= QuietTimeout) { // NB We don't reset QuietTimer, so we will trigger at next tick again // (assuming load is still low) // Sort from low to high batteries.Sort(batteryComparer); // Any batteries actively discharging? if (batteryDetails.CurrentPowerOutput > 0.0f) { // Take a battery offline, starting with the least charged. // Note, we cannot actually start recharging until they are all offline DisableOneBattery(batteries, totalDetails); } else { // All batteries are down, enable one for charging // (repeat next tick until we break low threshold, in which case QuietTimer // will reset) // But first, check if it would put us over the threshold var first = batteries[0]; // Assume all the same var wouldBeOutput = otherDetails.CurrentPowerOutput + first.DefinedPowerOutput; // Assume MaxPowerOutput = MaxPowerInput (not available to us) //commons.Echo("Would-be Output: " + ZACommons.FormatPower(wouldBeOutput)); var wouldBeLoad = wouldBeOutput / otherDetails.MaxPowerOutput; //commons.Echo("Would-be Load: " + wouldBeLoad); if (wouldBeLoad <= POWER_MANAGER_HIGH_LOAD_THRESHOLD) { RechargeOneBattery(batteries); } } } } else { QuietTimer = TimeSpan.FromSeconds(0); } }