-
-
Save InternetUnexplorer/ea13f1713d325b914126bcfb9b35e6fd to your computer and use it in GitHub Desktop.
| local state, data, reactor, turbine, info_window, rules_window | |
| local STATES = { | |
| READY = 1, -- Reactor is off and can be started with the lever | |
| RUNNING = 2, -- Reactor is running and all rules are met | |
| ESTOP = 3, -- Reactor is stopped due to rule(s) being violated | |
| UNKNOWN = 4, -- Reactor or turbine peripherals are missing | |
| } | |
| ------------------------------------------------ | |
| local rules = {} | |
| local function add_rule(name, fn) | |
| table.insert(rules, function() | |
| local ok, rule_met, value = pcall(fn) | |
| if ok then | |
| return rule_met, string.format("%s (%s)", name, value) | |
| else | |
| return false, name | |
| end | |
| end) | |
| end | |
| add_rule("REACTOR TEMPERATURE <= 745K", function() | |
| local value = string.format("%3dK", math.ceil(data.reactor_temp)) | |
| return data.reactor_temp <= 745, value | |
| end) | |
| add_rule("REACTOR DAMAGE <= 10%", function() | |
| local value = string.format("%3d%%", math.ceil(data.reactor_damage * 100)) | |
| return data.reactor_damage <= 0.10, value | |
| end) | |
| add_rule("REACTOR COOLANT LEVEL >= 95%", function() | |
| local value = string.format("%3d%%", math.floor(data.reactor_coolant * 100)) | |
| return data.reactor_coolant >= 0.95, value | |
| end) | |
| add_rule("REACTOR WASTE LEVEL <= 90%", function() | |
| local value = string.format("%3d%%", math.ceil(data.reactor_waste * 100)) | |
| return data.reactor_waste <= 0.90, value | |
| end) | |
| add_rule("TURBINE ENERGY LEVEL <= 95%", function() | |
| local value = string.format("%3d%%", math.ceil(data.turbine_energy * 100)) | |
| return data.turbine_energy <= 0.95, value | |
| end) | |
| local function all_rules_met() | |
| for i, rule in ipairs(rules) do | |
| if not rule() then | |
| return false | |
| end | |
| end | |
| -- Allow manual emergency stop with SCRAM button | |
| return state ~= STATES.RUNNING or data.reactor_on | |
| end | |
| ------------------------------------------------ | |
| local function update_data() | |
| data = { | |
| lever_on = redstone.getInput("top"), | |
| reactor_on = reactor.getStatus(), | |
| reactor_burn_rate = reactor.getBurnRate(), | |
| reactor_max_burn_rate = reactor.getMaxBurnRate(), | |
| reactor_temp = reactor.getTemperature(), | |
| reactor_damage = reactor.getDamagePercent(), | |
| reactor_coolant = reactor.getCoolantFilledPercentage(), | |
| reactor_waste = reactor.getWasteFilledPercentage(), | |
| turbine_energy = turbine.getEnergyFilledPercentage(), | |
| } | |
| end | |
| ------------------------------------------------ | |
| local function colored(text, fg, bg) | |
| term.setTextColor(fg or colors.white) | |
| term.setBackgroundColor(bg or colors.black) | |
| term.write(text) | |
| end | |
| local function make_section(name, x, y, w, h) | |
| for row = 1, h do | |
| term.setCursorPos(x, y + row - 1) | |
| local char = (row == 1 or row == h) and "\127" or " " | |
| colored("\127" .. string.rep(char, w - 2) .. "\127", colors.gray) | |
| end | |
| term.setCursorPos(x + 2, y) | |
| colored(" " .. name .. " ") | |
| return window.create(term.current(), x + 2, y + 2, w - 4, h - 4) | |
| end | |
| local function update_info() | |
| local prev_term = term.redirect(info_window) | |
| term.clear() | |
| term.setCursorPos(1, 1) | |
| if state == STATES.UNKNOWN then | |
| colored("ERROR RETRIEVING DATA", colors.red) | |
| return | |
| end | |
| colored("REACTOR: ") | |
| colored(data.reactor_on and "ON " or "OFF", data.reactor_on and colors.green or colors.red) | |
| colored(" LEVER: ") | |
| colored(data.lever_on and "ON " or "OFF", data.lever_on and colors.green or colors.red) | |
| colored(" R. LIMIT: ") | |
| colored(string.format("%4.1f", data.reactor_burn_rate), colors.blue) | |
| colored("/", colors.lightGray) | |
| colored(string.format("%4.1f", data.reactor_max_burn_rate), colors.blue) | |
| term.setCursorPos(1, 3) | |
| colored("STATUS: ") | |
| if state == STATES.READY then | |
| colored("READY, flip lever to start", colors.blue) | |
| elseif state == STATES.RUNNING then | |
| colored("RUNNING, flip lever to stop", colors.green) | |
| elseif state == STATES.ESTOP and not all_rules_met() then | |
| colored("EMERGENCY STOP, safety rules violated", colors.red) | |
| elseif state == STATES.ESTOP then | |
| colored("EMERGENCY STOP, toggle lever to reset", colors.red) | |
| end -- STATES.UNKNOWN cases handled above | |
| term.redirect(prev_term) | |
| end | |
| local estop_reasons = {} | |
| local function update_rules() | |
| local prev_term = term.redirect(rules_window) | |
| term.clear() | |
| if state ~= STATES.ESTOP then | |
| estop_reasons = {} | |
| end | |
| for i, rule in ipairs(rules) do | |
| local ok, text = rule() | |
| term.setCursorPos(1, i) | |
| if ok and not estop_reasons[i] then | |
| colored("[ OK ] ", colors.green) | |
| colored(text, colors.lightGray) | |
| else | |
| colored("[ FAIL ] ", colors.red) | |
| colored(text, colors.red) | |
| estop_reasons[i] = true | |
| end | |
| end | |
| term.redirect(prev_term) | |
| end | |
| ------------------------------------------------ | |
| local function main_loop() | |
| -- Search for peripherals again if one or both are missing | |
| if not state or state == STATES.UNKNOWN then | |
| reactor = peripheral.find("fissionReactorLogicAdapter") | |
| turbine = peripheral.find("turbineValve") | |
| end | |
| if not pcall(update_data) then | |
| -- Error getting data (either reactor or turbine is nil?) | |
| data = {} | |
| state = STATES.UNKNOWN | |
| elseif data.reactor_on == nil then | |
| -- Reactor is not connected | |
| state = STATES.UNKNOWN | |
| elseif data.turbine_energy == nil then | |
| -- Turbine is not connected | |
| state = STATES.UNKNOWN | |
| elseif not state then | |
| -- Program just started, get current state from lever | |
| state = data.lever_on and STATES.RUNNING or STATES.READY | |
| elseif state == STATES.READY and data.lever_on then | |
| -- READY -> RUNNING | |
| state = STATES.RUNNING | |
| -- Activate reactor | |
| pcall(reactor.activate) | |
| data.reactor_on = true | |
| elseif state == STATES.RUNNING and not data.lever_on then | |
| -- RUNNING -> READY | |
| state = STATES.READY | |
| elseif state == STATES.ESTOP and not data.lever_on then | |
| -- ESTOP -> READY | |
| state = STATES.READY | |
| elseif state == STATES.UNKNOWN then | |
| -- UNKNOWN -> ESTOP | |
| state = data.lever_on and STATES.ESTOP or STATES.READY | |
| estop_reasons = {} | |
| end | |
| -- Always enter ESTOP if safety rules are not met | |
| if state ~= STATES.UNKNOWN and not all_rules_met() then | |
| state = STATES.ESTOP | |
| end | |
| -- SCRAM reactor if not running | |
| if state ~= STATES.RUNNING and reactor then | |
| pcall(reactor.scram) | |
| end | |
| -- Update info and rules windows | |
| pcall(update_info) | |
| pcall(update_rules) | |
| sleep() -- Other calls should already yield, this is just in case | |
| return main_loop() | |
| end | |
| term.setPaletteColor(colors.black, 0x000000) | |
| term.setPaletteColor(colors.gray, 0x343434) | |
| term.setPaletteColor(colors.lightGray, 0xababab) | |
| term.setPaletteColor(colors.red, 0xdb2d20) | |
| term.setPaletteColor(colors.green, 0x01a252) | |
| term.setPaletteColor(colors.blue, 0x01a0e4) | |
| term.clear() | |
| local width = term.getSize() | |
| info_window = make_section("INFORMATION", 2, 2, width - 2, 7) | |
| rules_window = make_section("SAFETY RULES", 2, 10, width - 2, 9) | |
| parallel.waitForAny(main_loop, function() | |
| os.pullEventRaw("terminate") | |
| end) | |
| os.reboot() |
@Derrick355 As it's written, the safety rules are never supposed to be violated; what I usually do is either modify this program (or add another computer, to keep concerns separate) that constantly adjusts the reactor's burn rate linearly between 100% and 0% at e.g. 75% and 90% turbine energy. This makes it so that only enough power is generated to meet demand, and the turbine energy doesn't exceed 90% (with the 95% limit still there in case something goes wrong).
Do you have the script that can do that? (I'm not that great at coding in lua but I can do a bit)
@Derrick355 Sure, try inserting this on line 215 and it should adjust the burn rate linearly between 100% at ≤50% turbine energy and 0% at ≥75% turbine energy:
-- Update max burn rate to keep turbine below 75% energy
if state ~= STATES.UNKNOWN then
local tgt_burn_pct = math.min(math.max(0.0, 1 - (data.turbine_energy - 0.5) / 0.25), 1.0)
pcall(reactor.setBurnRate, tgt_burn_pct * data.reactor_max_burn_rate)
endI can change data.reactor_max_burn_rate if I want to set a manual cap on max burn rate, right?
If I let it go to the max burn rate it instantly vaporizes a lot of water and the reactor will auto shutoff
Also, if I want to change the 75% and 50% values, what do I edit?
@Derrick355 Yes, you can replace reactor_max_burn_rate with a constant (in mB/t) if you want a manual cap.
The function is math.min(math.max(0.0, 1 - (data.turbine_energy - A) / B), 1.0), where:
Ais the lower limit (currently0.5 = 50%), andA + Bis the upper limit (currently0.5 + 0.25 = 0.75 = 75%).
Hey, this might be a stupid question but how do i need to connect the computer to the reactor and what should the mode of the redstone logic adapter be?
i tried it with a modem to the logic adapter and every mode possible on the logic adapter. I also tried just sticking the computer directly to the logic adapter but nothing worked. im a bit lost here.
It always says failed to retrive data.
thanks in advance.
Edit:
Nvmd i figured it out. I forgot to connect the turbine.
Hey this code is exactly what I was looking for. Do you know if there is a way to have the display scale to any size?
@Kekalicious Hi! So, unfortunately I wrote this in a hurry and designed the UI around one specific size (built-in screen of an advanced computer) since it's easier to make everything look nice for a fixed size.
That said, it shouldn't be too hard to change; it's not a very complicated program, and so it should be easy to tweak it as needed to fit your situation. :)
@GeilesLuder connect the turbine to what?
I am also having some issues with the connection.
@GeilesLuder connect the turbine to what? I am also having some issues with the connection.
Hey, you also need to connect the turbine to the computer(via modem, same as the reactor itself). I forgot that initially.
how do i use rednet with this instead of wired routers?
@Derrick355 As it's written, the safety rules are never supposed to be violated; what I usually do is either modify this program (or add another computer, to keep concerns separate) that constantly adjusts the reactor's burn rate linearly between 100% and 0% at e.g. 75% and 90% turbine energy. This makes it so that only enough power is generated to meet demand, and the turbine energy doesn't exceed 90% (with the 95% limit still there in case something goes wrong).