Advertisement
Flawedspirit

OpenComputer Reactor Monitor

Jun 20th, 2015
2,325
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 18.01 KB | None | 0 0
  1. --[[
  2. This program lets you monitor and actively control a Big Reactors reactor and turbines with an OpenComputers computer.
  3.  
  4. This program was tested on and designed to work with the mod versions and configurations installed on Flawedspirit's Mental Instability Pack, though as the pack uses default settings for both Big Reactors and OpenComputers, there should be no issues using a different modpack, or even a modpack that makes changes to how BR works.
  5.  
  6. - http://technicpack.net/modpack/mi-reloaded.604813
  7. - https://flawedspirit.com/minecraft/#pack
  8.  
  9. Computer Design
  10. ------------------------
  11. Please note that to keep the code (relatively) simple, the program makes a few assumptions; those being:
  12.  
  13. - A Tier 3 Computer
  14. - A Tier 2 or better Graphics Card
  15. - An Internet Card
  16. - One Tier 2 screen OR one Tier 3 screen (for best results)
  17. - One reactor
  18. - Any number of (or zero) turbines
  19.  
  20. Notes
  21. ------------------------
  22. - Only one reactor has been tested with this program (additional reactors added AT OWN RISK)
  23. - Data for only 6 turbines will display onscreen if using a Tier 2 screen
  24. - Data for up to 28 turbines will display onscreen if using a Tier 3 screen
  25. - Data for ALL turbines will still be tallied in the 'totals' row
  26. - By default, the program updates once every 2 seconds, though the rate is adjustable
  27.  
  28. Features
  29. ------------------------
  30. - Dynamic tracking of reactor information, like temperature, fuel/waste levels, coolant levels*, steam output*, or RF storage*
  31. - Dynamic tracking of up to 6 turbines, including speed, steam input, RF generation, and RF storage
  32. - In-program control of reactor power and control rod settings
  33. - Real-time warning if certain parameters indicate abnormal or non-optimal operation of reactors/turbines
  34. - NEW! Turbine auto mode! Set it to either 900 or 1800 RPM by pressing T and the program will toggle your turbines' induction coils or active state to keep it at the right speed**
  35.  
  36. * If applicable
  37. ** Note: the author takes no responsibility if you bankrupt your base's energy stores because your turbines are all disengaged. Please use responsibly.
  38.  
  39. Usage
  40. ------------------------
  41. - Press the left and right arrow keys to toggle between page 1 (turbine/RF storage information) or 2 (control rod configuration)
  42. - Press L or , to lower/raise control rods by 1%
  43. - Press ; or . to lower/raise control rods by 5%
  44. - Press ' or / to lower/raise control rods by 10%
  45. - Press P to toggle reactor power
  46. - Press Q to exit the program and return to your computer's terminal prompt
  47. - Press T to toggle 'Auto Mode' on all turbines. This will engage the induction coil when your preferred rotational speed (900 or 1800 RPM) is reached
  48.  
  49. Resources
  50. ------------------------
  51. - This script is available from:
  52.   = http://pastebin.com/zWju7H0z
  53. - Official OpenComputers Site: http://ocdoc.cil.li/
  54. - Official Big Reactors Site: http://www.big-reactors.com/#/
  55. - Big Reactors API: http://wiki.technicpack.net/Reactor_Computer_Port
  56.  
  57. Changelog
  58. ------------------------
  59. - 0.1.6
  60.   - Fixed a bug that caused the program to crash when run on a Tier 2 screen
  61. - 0.1.5
  62.   - Addition of turbine auto mode
  63.   - Changes to make the program take better advantage of larger screen sizes
  64.   - Bug fixes
  65. - 0.1.4
  66.   - First release to Github! :D
  67.  
  68. TODO
  69. ------------------------
  70. - See https://github.com/Flawedspirit/FlawedspiritOC/issues for any outstanding issues.
  71. - Fix screen flickering issue on Page 1 (may not be possible at the moment)
  72. ]]
  73.  
  74. local component = require("component")
  75. local event = require("event")
  76. local keyboard = require("keyboard")
  77. local os = require("os")
  78. local term = require("term")
  79.  
  80. local pollRate = 2 -- Change to whatever value you'd like; time is in seconds
  81. local active = true
  82. local currentPage = 1
  83. local turbineAutoMode = 0 -- This can be changed to 900 or 1800 if you want
  84.  
  85. -- Static Text Elements
  86. local header = "Reactor: "
  87. local headerOutput = "Running at %d%% max rated output"
  88. local version = "v0.1.6"
  89.  
  90. -- Components
  91. local gpu = component.gpu
  92. local reactor = component.br_reactor
  93. local w, h = gpu.getResolution()
  94.  
  95. local turbine = {}
  96. local i = 1
  97. for address, type in component.list("br_turbine") do
  98.   turbine[i] = component.proxy(address)
  99.   i = i + 1
  100. end
  101.  
  102. -- Reactor/turbine Data
  103. local totalControlRodLevel = 0
  104. local turbineMaxSteamIn = 0
  105. local controlRods = {}
  106. local reactorStatus = {}
  107.  
  108. -- Colors Helper
  109. local colors = {}
  110. colors.white      = 0xFFFFFF
  111. colors.orange     = 0xFFA500
  112. colors.magenta    = 0xFF00FF
  113. colors.lightblue  = 0x00AEEF
  114. colors.yellow     = 0xFFFF00
  115. colors.lime       = 0x00FF00
  116. colors.pink       = 0xFFC0CB
  117. colors.gray       = 0x555555
  118. colors.grey       = 0x555555
  119. colors.silver     = 0xAAAAAA
  120. colors.cyan       = 0x00FFFF
  121. colors.purple     = 0x800080
  122. colors.blue       = 0x0000FF
  123. colors.brown      = 0x603913
  124. colors.green      = 0x008000
  125. colors.red        = 0xFF0000
  126. colors.black      = 0x000000
  127.  
  128. -- Returns a whole number expressing a percentage
  129. -- out of 100 e.g. 90 is 90%
  130. function percent(val, max)
  131.   return (val / max) * 100
  132. end
  133.  
  134. function hLine(row)
  135.   gpu.fill(1, row, w, 1, "─")
  136. end
  137.  
  138. function label(x, y, message, color, ...)
  139.   local color = color or gpu.getForeground()
  140.   local oldColor = gpu.getForeground()
  141.  
  142.   gpu.setForeground(color)
  143.   term.setCursor(x, y)
  144.   print(string.format(message, ...))
  145.   gpu.setForeground(oldColor)
  146. end
  147.  
  148. function box(row, message, color)
  149.   --gpu.fill(1, row, w, row + 3, " ")
  150.   local color = color or gpu.getForeground()
  151.   local oldColor = gpu.getForeground()
  152.  
  153.   term.setCursor(1, row)
  154.   gpu.setForeground(color)
  155.  
  156.   -- Corners
  157.   gpu.set(1, row, "╒")
  158.   gpu.set(w, row, "╕")
  159.   gpu.set(1, row + 2, "└")
  160.   gpu.set(w, row + 2, "┘")
  161.  
  162.   -- Left and right
  163.   gpu.set(1, row + 1, "│")
  164.   gpu.set(w, row + 1, "│")
  165.  
  166.   -- Top and bottom
  167.   gpu.fill(2, row, w - 2, 1, "═")
  168.   gpu.fill(2, row + 2, w - 2, 1, "─")  
  169.  
  170.   gpu.set(3, row + 1, message)
  171.   gpu.setForeground(oldColor)
  172. end
  173.  
  174. -- Displayed if a reactor cannot be found at all
  175. -- and this program is rendered useless
  176. function printNoSignal()
  177.   icon = "[ ! ] "
  178.   message = "No Signal"
  179.  
  180.   gpu.setBackground(colors.black)
  181.   gpu.fill(1, 1, w, h, " ")
  182.  
  183.   gpu.setForeground(colors.red)
  184.   gpu.set(w / 2 - (string.len(icon) + string.len(message)) / 2 + 1, (h / 2) + 1, "[ ! ]")
  185.  
  186.   gpu.setForeground(colors.white)
  187.   gpu.set((w / 2) - 1, (h / 2) + 1, message)
  188. end
  189.  
  190. function printControlHelp()
  191.   hLine(h - 5)
  192.   label(1, h - 4, "%s", nil, "l / ,")
  193.   label(16, h - 4, "%s", nil, "; / .")
  194.   label(32, h - 4, "%s", nil, "' / /")
  195.   label(48, h - 4, "%s", nil, "p")
  196.   label(64, h - 4, "%s", nil, "q")
  197.  
  198.   label(1, h - 3, "%s", colors.gray, "Rods +1/-1")
  199.   label(16, h - 3, "%s", colors.gray, "Rods +5/-5")
  200.   label(32, h - 3, "%s", colors.gray, "Rods +10/-10")
  201.   label(48, h - 3, "%s", colors.gray, "Reactor Power")
  202.   label(64, h - 3, "%s", colors.gray, "Quit")
  203.  
  204.   if w > 80 then
  205.     label(80, h - 4, "%s", nil, "t")
  206.     label(80, h - 3, "%s", colors.gray, "Turbine Auto Mode")
  207.   end
  208. end
  209. function toggleAutoMode()
  210.   if turbineAutoMode == 0 then
  211.     turbineAutoMode = 900
  212.   elseif turbineAutoMode == 900 then
  213.     turbineAutoMode = 1800
  214.   elseif turbineAutoMode == 1800 then
  215.     turbineAutoMode = 0
  216.   else
  217.     turbineAutoMode = 0
  218.   end
  219. end
  220.  
  221. -- Event handler for when a key is pressed
  222. function onKeyDown(key)
  223.   local event, address, _, key, _ = event.pull()
  224.   if key == keyboard.keys.right then
  225.     currentPage = 2
  226.     gpu.fill(1, 1, w, h, " ")
  227.   elseif key == keyboard.keys.left then
  228.     currentPage = 1
  229.     gpu.fill(1, 1, w, h, " ")
  230.   elseif key == keyboard.keys.l then
  231.     reactor.setAllControlRodLevels(totalControlRodLevel + 1)
  232.   elseif key == keyboard.keys.comma then
  233.     reactor.setAllControlRodLevels(totalControlRodLevel - 1)
  234.   elseif key == keyboard.keys.semicolon then
  235.     reactor.setAllControlRodLevels(totalControlRodLevel + 5)
  236.   elseif key == keyboard.keys.period then
  237.     reactor.setAllControlRodLevels(totalControlRodLevel -5)
  238.   elseif key == keyboard.keys.apostrophe then
  239.     reactor.setAllControlRodLevels(totalControlRodLevel + 10)
  240.   elseif key == keyboard.keys.slash then
  241.     reactor.setAllControlRodLevels(totalControlRodLevel - 10)
  242.   elseif key == keyboard.keys.p then
  243.     reactor.setActive(not reactor.getActive())
  244.   elseif key == keyboard.keys.q then
  245.     active = false
  246.   elseif key == keyboard.keys.t then
  247.     toggleAutoMode()
  248.   end
  249. end
  250.  
  251. -- Listen for "key_down" event to control program flow
  252. event.listen("key_down", onKeyDown)
  253.  
  254. while active do
  255.   gpu.fill(1, 1, w, h, " ")
  256.   if component.isAvailable("br_reactor") then
  257.     label(w - (string.len(version) + 1), h - 1, version, colors.gray)
  258.     box(1, header, nil)
  259.  
  260.     -- Get and update values of each control rod
  261.     for i = 1, reactor.getNumberOfControlRods() - 1 do
  262.       controlRods[i] = reactor.getControlRodLevel(i)
  263.     end
  264.  
  265.     -- Iterate through and take the sum of each control rod level
  266.     -- Average it to get total control rod level
  267.     totalControlRodLevel = 0
  268.     for i = 1, #controlRods do
  269.       totalControlRodLevel = totalControlRodLevel + controlRods[i]
  270.     end
  271.     totalControlRodLevel = totalControlRodLevel / #controlRods
  272.  
  273.     -- Update reactor data
  274.     reactorStatus.temperature      = {"Temp", reactor.getCasingTemperature()}
  275.     reactorStatus.fuel             = {"Fuel", reactor.getFuelAmount()}
  276.     reactorStatus.waste            = {"Waste", reactor.getWasteAmount()}
  277.     reactorStatus.fuelMax          = {"Max Fuel", reactor.getFuelAmountMax()}
  278.     reactorStatus.burnRate         = {"Burn Rate", reactor.getFuelConsumedLastTick()}
  279.     reactorStatus.reactivity       = {"Reactivity", reactor.getFuelReactivity()}
  280.     reactorStatus.coolant          = {"Coolant", reactor.getCoolantAmount()}
  281.     reactorStatus.coolantMax       = {"Max Coolant", reactor.getCoolantAmountMax()}
  282.     reactorStatus.steam            = {"Steam Out", reactor.getHotFluidProducedLastTick()}
  283.     reactorStatus.steamMax         = {"Max Steam", reactor.getHotFluidAmountMax()}
  284.     reactorStatus.storedRF         = {"Stored Power", reactor.getEnergyStored()}
  285.  
  286.     label(1, 4, "%s: %.3f mB/t (%s: %d%%)", nil, reactorStatus.burnRate[1], reactorStatus.burnRate[2], reactorStatus.reactivity[1], reactorStatus.reactivity[2])
  287.  
  288.     -- REACTOR TABLE
  289.     -- Table header
  290.     label(1, 6, "%s", nil, reactorStatus.temperature[1])
  291.     label(16, 6, "%s", nil, reactorStatus.fuel[1])
  292.     label(32, 6, "%s", nil, reactorStatus.waste[1])
  293.     label(48, 6, "%s", nil, reactorStatus.coolant[1])
  294.     label(64, 6, "%s", nil, reactorStatus.steam[1])
  295.     hLine(7)
  296.  
  297.     -- Table body
  298.     label(1, 8, "%d °C", colors.red, reactorStatus.temperature[2])
  299.  
  300.     if percent(reactorStatus.fuel[2], reactorStatus.fuelMax[2]) > 10 then
  301.       label(16, 8, "%d mB", nil, reactorStatus.fuel[2])
  302.     else
  303.       label(16, 8, "%d mB [!]", colors.red, reactorStatus.fuel[2])
  304.     end
  305.  
  306.     if percent(reactorStatus.waste[2], reactorStatus.fuelMax[2]) < 90 then
  307.       label(32, 8, "%d mB", nil, reactorStatus.waste[2])
  308.     else
  309.       label(32, 8, "%d mB [!]", colors.red, reactorStatus.waste[2])
  310.     end
  311.  
  312.     if percent(reactorStatus.coolant[2], reactorStatus.coolantMax[2]) > 10 then
  313.       label(48, 8, "%d mB", nil, reactorStatus.fuel[2])
  314.     else
  315.       label(48, 8, "%d mB [!]", colors.red, reactorStatus.coolant[2])
  316.     end
  317.    
  318.     if reactorStatus.steam[2] >= turbineMaxSteamIn then
  319.       label(64, 8, "%d mB/t", nil, reactorStatus.steam[2])
  320.     else
  321.       label(64, 8, "%d mB/t [!]", colors.red, reactorStatus.steam[2])
  322.     end
  323.  
  324.     -- Percentages
  325.     label(16, 9, "(%.1f%%)", colors.gray, percent(reactorStatus.fuel[2], reactorStatus.fuelMax[2]))
  326.     label(32, 9, "(%.1f%%)", colors.gray, percent(reactorStatus.waste[2], reactorStatus.fuelMax[2]))
  327.     label(48, 9, "(%.1f%%)", colors.gray, percent(reactorStatus.coolant[2], reactorStatus.coolantMax[2]))
  328.     label(64, 9, "(%.1f%%)", colors.gray, percent(reactorStatus.steam[2], reactorStatus.steamMax[2]))
  329.  
  330.     if reactor.getActive() then
  331.       label(string.len(header) + 3, 2, "ON", colors.lime)
  332.       label(w - string.len(headerOutput), 2, headerOutput, nil, (100 - totalControlRodLevel))
  333.     else
  334.       label(string.len(header) + 3, 2, "OFF", colors.red)
  335.       label((w + 1) - string.len(headerOutput), 2, headerOutput, nil, 0)
  336.     end
  337.  
  338.     if currentPage == 1 then
  339.       box(h - 2, "Press [→] to go to page 2", nil)
  340.  
  341.       if h > 25 then
  342.         printControlHelp()
  343.       end
  344.  
  345.       if component.isAvailable("br_turbine") then
  346.         -- TURBINE TABLE
  347.         -- Table header
  348.         label(1, 11, "%s", nil, "Turbine #")
  349.         label(16, 11, "%s", nil, "Speed")
  350.         label(32, 11, "%s", nil, "Steam In")
  351.         label(48, 11, "%s", nil, "RF Out")
  352.         label(64, 11, "%s", nil, "Stored RF")
  353.  
  354.         if w > 80 then
  355.           label(80, 11, "%s", nil, "Coil State")
  356.         end
  357.         hLine(12)
  358.  
  359.         -- Table body
  360.         -- Update turbine status
  361.         local turbineTotalSteamIn = 0
  362.               turbineMaxSteamIn = 0
  363.         local turbineTotalRFOut = 0
  364.         local turbineStoredRF = 0
  365.  
  366.         -- by default, only 6 turbines will fit on the screen
  367.         local maxTurbines = 0
  368.  
  369.         if h > 25 then
  370.           maxTurbines = math.min(#turbine, 28)
  371.           hOffset = 6
  372.         else
  373.           maxTurbines = math.min(#turbine, 6)
  374.           hOffset = 4
  375.         end
  376.  
  377.         if #turbine > maxTurbines then
  378.           label(1, h - (hOffset + 2), "...", colors.orange)
  379.           label(16, h - (hOffset + 2), "%d %s", colors.orange, (#turbine - 6), "turbine(s) not shown. Totals shown for all turbines.")
  380.         end
  381.  
  382.         for i = 1, #turbine do
  383.           turbineTotalSteamIn = turbineTotalSteamIn + turbine[i].getFluidFlowRate()
  384.           turbineMaxSteamIn = turbineMaxSteamIn + turbine[i].getFluidFlowRateMax()
  385.           turbineTotalRFOut = turbineTotalRFOut + turbine[i].getEnergyProducedLastTick()
  386.           turbineStoredRF = turbineStoredRF + turbine[i].getEnergyStored()
  387.  
  388.           -- Auto Mode (TM but not really) fun
  389.           if turbineAutoMode == 900 or turbineAutoMode == 1800 then
  390.             if turbineAutoMode == 900 and turbine[i].getRotorSpeed() < 895 or
  391.              turbineAutoMode == 1800 and turbine[i].getRotorSpeed() < 1795 then
  392.               turbine[i].setInductorEngaged(false)
  393.             else
  394.               turbine[i].setInductorEngaged(true)
  395.             end
  396.  
  397.             if turbineAutoMode == 900 and turbine[i].getRotorSpeed() > 920 or
  398.              turbineAutoMode == 1800 and turbine[i].getRotorSpeed() > 1820 then
  399.               turbine[i].setActive(false)
  400.             else
  401.               turbine[i].setActive(true)
  402.             end
  403.           end
  404.          
  405.           if w > 80 then
  406.             label(80, 11, "%s", nil, "Coil State")
  407.             label(96, 11, "%s", nil, "Status")
  408.           end
  409.         end
  410.  
  411.         for i = 1, maxTurbines do
  412.           label(1, 12 + i, "%d", nil, i)
  413.  
  414.           if turbine[i].getRotorSpeed() >= 895 and turbine[i].getRotorSpeed() <= 905 or
  415.            turbine[i].getRotorSpeed() >= 1795 and turbine[i].getRotorSpeed() <= 1805 then
  416.             label(16, 12 + i, "%.1f RPM", colors.cyan, turbine[i].getRotorSpeed())
  417.           elseif turbine[i].getRotorSpeed() >= 880 and turbine[i].getRotorSpeed() <= 920 or
  418.            turbine[i].getRotorSpeed() >= 1780 and turbine[i].getRotorSpeed() <= 1820 then
  419.             label(16, 12 + i, "%.1f RPM", colors.lime, turbine[i].getRotorSpeed())
  420.           elseif turbine[i].getRotorSpeed() >= 1821 then
  421.             label(16, 12 + i, "%.1f RPM [!]", colors.red, turbine[i].getRotorSpeed())
  422.           else
  423.             label(16, 12 + i, "%.1f RPM", colors.orange, turbine[i].getRotorSpeed())
  424.           end
  425.           label(32, 12 + i, "%d mB/t", nil, turbine[i].getFluidFlowRate())
  426.           label(48, 12 + i, "%d RF/t", nil, turbine[i].getEnergyProducedLastTick())
  427.           label(64, 12 + i, "%d RF", nil, turbine[i].getEnergyStored())
  428.  
  429.           if w > 80 then
  430.             if turbine[i].getInductorEngaged() then
  431.               label(80, 12 + i, "%s", colors.lime, "Engaged")
  432.             else
  433.               label(80, 12 + i, "%s", colors.red, "Disengaged")
  434.             end
  435.             if turbine[i].getRotorSpeed() >= 1821 then
  436.               label(96, 12 + i, "%s", colors.red, "Overspeed")
  437.             elseif turbine[i].getRotorSpeed() < 880 then
  438.               label(96, 12 + i, "%s", colors.red, "Underspeed")
  439.             elseif turbine[i].getActive() == false then
  440.               label(96, 12 + i, "%s", colors.gray, "Disabled")
  441.             else
  442.               label(96, 12 + i, "%s", nil, "Normal")
  443.             end
  444.           end
  445.         end
  446.  
  447.         hLine(h - (hOffset + 1))
  448.         label(1, h - (hOffset), "%s", nil, "TOTAL")
  449.         label(16, h - (hOffset), "%s", nil, "--")
  450.         label(32, h - (hOffset), "%d mB/t", nil, turbineTotalSteamIn)
  451.         label(48, h - (hOffset), "%d RF/t", nil, turbineTotalRFOut)
  452.         label(64, h - (hOffset), "%d RF", nil, turbineStoredRF)
  453.  
  454.         if turbineAutoMode == 0 then
  455.           label(80, h - (hOffset), "%s %s", nil, "Auto Mode:", "Off")
  456.         elseif turbineAutoMode == 900 then
  457.           label(80, h - (hOffset), "%s %s", nil, "Auto Mode:", "900 RPM")
  458.         elseif turbineAutoMode == 1800 then
  459.          label(80, h - (hOffset), "%s %s", nil, "Auto Mode:", "1800 RPM")
  460.         end
  461.       else
  462.         label(1, 11, "%s: %d RF", nil, reactorStatus.storedRF[1], reactorStatus.storedRF[2])
  463.         label(1, 13, "%s", nil, "No turbines were detected.")
  464.       end
  465.  
  466.       os.sleep(pollRate)
  467.     elseif currentPage == 2 then
  468.       local maxBarLength = (w - 11) - 11
  469.  
  470.       box(h - 2, "Press [←] to go to page 1", nil)
  471.       label(1, 11, "%s", nil, "Control Rods")
  472.       hLine(12)
  473.  
  474.       gpu.fill(11, 13, math.ceil(maxBarLength * (totalControlRodLevel / 100) + 0.5), 1, "=")
  475.       label(1, 13, "%s", nil, "ALL RODS [")
  476.       label(w - 10, 13, "%s %d%%", nil, "]", totalControlRodLevel)
  477.  
  478.       printControlHelp()
  479.       os.sleep(pollRate)
  480.     end
  481.   else
  482.     printNoSignal()
  483.   end
  484. end
  485.  
  486. -- Unregister key_down event on program exit or things get... weird...
  487. event.ignore("key_down", onKeyDown)
  488. term.clear()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement