-
-
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() |
Placing it on the top doesn´t work
Can you be more specific? Does the "LEVER" status in the UI change when you flip the lever?
Sorry, it does funktion, i was just stupid.
Thanks for your help
No worries, glad you got it working :)
So i have been succesfully using this code very well done! i was more wondering if i can be able to activate the fission remotely using perhaps another computer and also display it on monitors there.. this would be cross dimension though. i did some test and i believe it can communicate using ender modems but i cant get the stuff to work.
@DahleyvanH It's definitely possible (ender modems work across dimensions), but it will require a lot of changes! As I mentioned in another comment, this was designed for a very specific use-case (advanced computer controlled with a lever on top). I would be very cautious when modifying it since there can be a lot of not-so-obvious edge-cases for stuff like this, but it's definitely doable as long as you're careful! You could also consider moving the display and networking code to a second computer/program, and leaving the core control logic in place. You will have to make big changes to the code either way, so I think it mostly comes down to what you're comfortable with.
Hey Thanks to for the reply, i will not change the code as of now untill maybe i understand more about lua.. again great work on the code
hi, so using the program and works well but (not sure what MC and Mekanism generators version this was made for) for MC 1.19.2 and Mekanism generators 10.3.8.477 the damage value for the fission reactor seems to already be a percentage so if the reactor took 1% of damage then the program would end up reading as 100% so i had to go and remove *100 from the damage math and then it was reading it correctly.
so thought i give a heads up
Having issues trying to use this with a ender modem. Anyone have any solutions?
ok so for some reason whenever i pull the lever connected via a fission reactor logic adapter it turns on for a milisecond and then turns off
does anyone know how to fix this?
edit: i was too lazy to read the other comments
Is it possible to have the reactor turn itself back on if the only reason it stopped was because the turbine had too much power? Maybe so that if the turbine power went above 95% it stopped but if it goes back down to 50% or something it'll turn itself back on automatically?
@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).
@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)
end
I 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:
A
is the lower limit (currently0.5 = 50%
), andA + B
is 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?
You should be able to just place it on top of the computer :). If you want the redstone input to be on another side, you will have to change what is currently line 64.
The lever is nice because it lets you control the reactor without having to open the computer. I'm realizing now that I should probably update the gist with a description of my setup when I get a chance so people can use it more easily.