neuroticfox

Monitoring

Jun 12th, 2020 (edited)
283
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 16.72 KB | None | 0 0
  1. local component = require("component")
  2. local event = require("event")
  3. local term = require("term")
  4. local gpu = component.gpu
  5.  
  6.  -- Safety Checks
  7.  
  8. if not component.isAvailable("draconic_reactor") then
  9.   print("Reactor not connected. Please connect computer to reactor with an Adapter block.")
  10.   os.exit()
  11. end
  12. reactor = component.draconic_reactor
  13. local flux_gates = {}
  14. for x,y in pairs(component.list("flux_gate")) do
  15.   flux_gates[#flux_gates+1] = x
  16. end
  17. if #flux_gates < 2 then
  18.   print("Not enough flux gates connected; please connect inflow and outflow flux gates with Adapter blocks.")
  19.   os.exit()
  20. end
  21. flux_in = component.proxy(flux_gates[1])
  22. flux_out = component.proxy(flux_gates[2])
  23. if not flux_in or not flux_out then
  24.   print("Not enough flux gates connected; please connect inflow and outflow flux gates with Adapter blocks.")
  25.   os.exit()
  26. end
  27.  
  28.  -- Functions
  29.  
  30. function exit_msg(msg)
  31.   term.clear()
  32.   print(msg)
  33.   os.exit()
  34. end
  35.  
  36. local TO = 0
  37.  
  38. function modify_temp(offset)
  39.   local new_temp = ideal_temp + offset
  40.   if new_temp > 10000 and TO == 0 then
  41.     new_temp = 10000
  42.   elseif new_temp < 2000 then
  43.     new_temp = 2000
  44.   end
  45.   ideal_temp = new_temp
  46. end
  47.  
  48. function modify_field(offset)
  49.   local new_strength = ideal_strength + offset
  50.   if new_temp > 10001 then
  51.     new_strength = 55
  52.   end
  53.   ideal_strength = new_strength
  54. end
  55.  
  56. function modify_field(offset)
  57.   local new_strength = ideal_strength + offset
  58.   if new_strength > 100 then
  59.     new_strength = 100
  60.   elseif new_strength > -10 and new_strength < 0.5 then
  61.     new_strength = 0.5
  62.   end
  63.   ideal_strength = new_strength
  64. end
  65.  
  66.  -- Buttons
  67.  
  68. local adj_button_width = 19
  69. local temp_adjust_x_offset = 68
  70. local temp_adjust_y_offset = 2
  71. local field_adjust_x_offset = temp_adjust_x_offset + adj_button_width + 2
  72. local field_adjust_y_offset = 2
  73. local status = "PeFi"
  74. local lowest_field = 100
  75. local highest_temp = 0
  76. local highest_outflow = 0
  77. local buttons = {
  78.   start={
  79.     x=42,
  80.     y=2,
  81.     width=24,
  82.     height=7,
  83.     text="Start",
  84.     action=function()
  85.       if safe then
  86.         state = "Charging"
  87.         reactor.chargeReactor()
  88.       elseif shutting_down then
  89.         state = "Active"
  90.         reactor.activateReactor()
  91.       end
  92.     end,
  93.   },
  94.   shutdown={
  95.     x=42,
  96.     y=12,
  97.     width=24,
  98.     height=7,
  99.     text="Shutdown",
  100.     action=function()
  101.     cutoff_temp = 10500
  102.     ideal_temp = 8000
  103.     ideal_strength = 15
  104.     cutoff_field = 0.45
  105.       state = "Manual Shutdown"
  106.       reactor.stopReactor()
  107.     end,
  108.   },
  109.       chaosmode={
  110.     x=2,
  111.     y=34,
  112.     width=24,
  113.     height=3,
  114.     text=" Chaos Mode",
  115.     action=function()
  116.       cutoff_temp = 35000
  117.       cutoff_field = 5
  118.       ideal_strength = 55
  119.       ideal_temp = 30000
  120.       lowest_field = 200
  121.     end,
  122.     condition=function() return running end
  123.   },
  124.     analytics={
  125.     x=28,
  126.     y=34,
  127.     width=24,
  128.     height=3,
  129.     text="Reset Analytics",
  130.     action=function()
  131.       highest_temp = 0
  132.       lowest_field = 200
  133.       highest_outflow = 0
  134.       status = "PeFi"
  135.     end,
  136.   },
  137.     Explode={
  138.     x=28,
  139.     y=38,
  140.     width=24,
  141.     height=3,
  142.     text="Initiate Meltdown",
  143.     action=function()
  144.       ideal_strength = 0
  145.       ideal_temp = 30000
  146.     end,
  147.     condition=function() return running end
  148.   },
  149.     force_exit={
  150.     x=2,
  151.     y=38,
  152.     width=24,
  153.     height=3,
  154.     text="Force Exit",
  155.     action=function()
  156.       cutoff_temp = 10500
  157.       ideal_temp = 2000
  158.       ideal_strength = 50
  159.       cutoff_field = 0.45
  160.       state = "Manual Shutdown"
  161.       reactor.stopReactor()
  162.       event_loop = false
  163.     end,
  164.   },
  165.     switch_gates={
  166.     x=2,
  167.     y=34,
  168.     width=24,
  169.     height=3,
  170.     text="Swap flux gates",
  171.     action=function()
  172.       cutoff_temp = 10500
  173.       local old_addr = flux_in.address
  174.       flux_in = component.proxy(flux_out.address)
  175.       flux_out = component.proxy(old_addr)
  176.     end,
  177.     condition=function() return safe or shutting_down end
  178.   },
  179.     exit={
  180.     x=42,
  181.     y=22,
  182.     width=24,
  183.     height=7,
  184.     text="Exit",
  185.     action=function()
  186.       event_loop = false
  187.     end,
  188.     condition=function() return safe end
  189.   },
  190.   temp_up_max={
  191.     x=temp_adjust_x_offset,
  192.     y=temp_adjust_y_offset,
  193.     width=adj_button_width,
  194.     height=1,
  195.     text="Maximum",
  196.     action=function()
  197.       ideal_temp = 10500
  198.     end
  199.   },
  200.   temp_up_thousand={
  201.     x=temp_adjust_x_offset,
  202.     y=temp_adjust_y_offset+2,
  203.     width=adj_button_width,
  204.     height=1,
  205.     text="+1000",
  206.     action=function() modify_temp(1000) end
  207.   },
  208.   temp_up_hundred={
  209.     x=temp_adjust_x_offset,
  210.     y=temp_adjust_y_offset+4,
  211.     width=adj_button_width,
  212.     height=1,
  213.     text="+100",
  214.     action=function() modify_temp(100) end
  215.   },
  216.   temp_up_ten={
  217.     x=temp_adjust_x_offset,
  218.     y=temp_adjust_y_offset+6,
  219.     width=adj_button_width,
  220.     height=1,
  221.     text="+10",
  222.     action=function() modify_temp(10) end
  223.   },
  224.   temp_up_one={
  225.     x=temp_adjust_x_offset,
  226.     y=temp_adjust_y_offset+8,
  227.     width=adj_button_width,
  228.     height=1,
  229.     text="+1",
  230.     action=function() modify_temp(1) end
  231.   },
  232.   temp_down_thousand={
  233.     x=temp_adjust_x_offset,
  234.     y=temp_adjust_y_offset+18,
  235.     width=adj_button_width,
  236.     height=1,
  237.     text="-1000",
  238.     action=function() modify_temp(-1000) end
  239.   },
  240.     temp_down_max={
  241.     x=temp_adjust_x_offset,
  242.     y=temp_adjust_y_offset+20,
  243.     width=adj_button_width,
  244.     height=1,
  245.     text="Minimum",
  246.     action=function() modify_temp(-20000) end
  247.   },
  248.     TO={
  249.     x=temp_adjust_x_offset,
  250.     y=temp_adjust_y_offset+24,
  251.     width=adj_button_width,
  252.     height=1,
  253.     text="Unlock Temp",
  254.     action=function()
  255.       cutoff_temp = 13000
  256.       TO = 1
  257.     end
  258.   },
  259.   temp_down_hundred={
  260.     x=temp_adjust_x_offset,
  261.     y=temp_adjust_y_offset+16,
  262.     width=adj_button_width,
  263.     height=1,
  264.     text="-100",
  265.     action=function() modify_temp(-100) end
  266.   },
  267.   temp_down_ten={
  268.     x=temp_adjust_x_offset,
  269.     y=temp_adjust_y_offset+14,
  270.     width=adj_button_width,
  271.     height=1,
  272.     text="-10",
  273.     action=function() modify_temp(-10) end
  274.   },
  275.   temp_down_one={
  276.     x=temp_adjust_x_offset,
  277.     y=temp_adjust_y_offset+12,
  278.     width=adj_button_width,
  279.     height=1,
  280.     text="-1",
  281.     action=function() modify_temp(-1) end
  282.   },
  283.   field_up_ten={
  284.     x=field_adjust_x_offset,
  285.     y=field_adjust_y_offset+3,
  286.     width=adj_button_width,
  287.     height=1,
  288.     text="+10",
  289.     action=function() modify_field(10) end
  290.   },
  291.     field_up_one={
  292.     x=field_adjust_x_offset,
  293.     y=field_adjust_y_offset+5,
  294.     width=adj_button_width,
  295.     height=1,
  296.     text="+1",
  297.     action=function() modify_field(1) end
  298.   },
  299.   field_up_tenth={
  300.     x=field_adjust_x_offset,
  301.     y=field_adjust_y_offset+7,
  302.     width=adj_button_width,
  303.     height=1,
  304.     text="+0.1",
  305.     action=function() modify_field(0.1) end
  306.   },
  307.   field_down_ten={
  308.     x=field_adjust_x_offset,
  309.     y=field_adjust_y_offset+17,
  310.     width=adj_button_width,
  311.     height=1,
  312.     text="-10",
  313.     action=function() modify_field(-10) end
  314.   },
  315.     field_down_one={
  316.     x=field_adjust_x_offset,
  317.     y=field_adjust_y_offset+15,
  318.     width=adj_button_width,
  319.     height=1,
  320.     text="-1",
  321.     action=function() modify_field(-1) end
  322.   },
  323.   field_down_tenth={
  324.     x=field_adjust_x_offset,
  325.     y=field_adjust_y_offset+13,
  326.     width=adj_button_width,
  327.     height=1,
  328.     text="-0.1",
  329.     action=function() modify_field(-0.1) end
  330.   },
  331.   BypassField={
  332.     x=field_adjust_x_offset,
  333.     y=field_adjust_y_offset+24,
  334.     width=adj_button_width,
  335.     height=1,
  336.     text="Bypass Cutoff",
  337.     action=function()
  338.       cutoff_field = 0.1
  339.     end
  340.   }
  341. }
  342.  
  343.  -- main code
  344.  
  345. flux_in.setFlowOverride(0)
  346. flux_out.setFlowOverride(0)
  347. flux_in.setOverrideEnabled(true)
  348. flux_out.setOverrideEnabled(true)
  349.  
  350. local condition = reactor.getReactorInfo()
  351. if not condition then
  352.   print("Reactor not initialized, please ensure the stabilizers are properly laid out.")
  353.   os.exit()
  354. end
  355.  
  356. ideal_strength = 15
  357. ideal_temp = 8000
  358. cutoff_temp = 10500
  359. cutoff_field = 0.45
  360.  
  361.  -- tweakable pid gains
  362.  
  363. inflow_P_gain = 1
  364. inflow_I_gain = 0.04
  365. inflow_D_gain = 0.1
  366.  
  367. outflow_P_gain = 500
  368. outflow_I_gain = 0.5
  369. outflow_II_gain = 0.0000003
  370. outflow_D_gain = 60000
  371.  
  372.  -- initialize main loop
  373.  
  374. inflow_I_sum = 0
  375. inflow_D_last = 0
  376.  
  377. outflow_I_sum = 0
  378. outflow_II_sum = 0
  379. outflow_D_last = 0
  380.  
  381. state = "Standby"
  382. shutting_down = false
  383.  
  384. if condition.temperature > 25 then
  385.   state = "Cooling"
  386. end
  387. if condition.temperature > 2000 then
  388.   state = "Active"
  389. end
  390.  
  391.  -- Possible states:
  392.   --Standby
  393.   --Charging
  394.   --Active
  395.   --Manual Shutdown
  396.   --Emergency Shutdown
  397.   --Cooling
  398.  
  399. event_loop = true
  400. while event_loop do
  401.  
  402.   if not component.isAvailable("draconic_reactor") then
  403.     exit_msg("Reactor disconnected, exiting")
  404.   end
  405.  
  406.   if not component.isAvailable("flux_gate") then
  407.     exit_msg("Flux gates disconnected, exiting")
  408.   end
  409.  
  410.   local info = reactor.getReactorInfo()
  411.  
  412.  -- Highest Heat Value
  413.  
  414. if info.temperature > highest_temp then
  415.   highest_temp = info.temperature
  416. end
  417.  
  418.  -- Lowest Field Value
  419.  
  420. if ((info.fieldStrength / info.maxFieldStrength) * 100) < lowest_field then
  421.   lowest_field = ((info.fieldStrength / info.maxFieldStrength) * 100)
  422. end
  423.  
  424.  
  425.   local inflow = 0
  426.   local outflow = 0
  427.  
  428.   shutting_down = state == "Manual Shutdown" or state == "Emergency Shutdown"
  429.   running = state == "Charging" or state == "Active"
  430.   safe = state == "Standby" or state == "Cooling"
  431.  
  432.   if state == "Charging" then
  433.     inflow = 50000000
  434.  
  435.  
  436.     if info.temperature > 2000 then
  437.       reactor.activateReactor()
  438.       state = "Active"
  439.     end
  440.   elseif state == "Cooling" then
  441.     if info.temperature < 25 then
  442.       state = "Standby"
  443.     end
  444.     inflow = 10
  445.     outflow = 20
  446.   elseif state == "Standby" then
  447.     inflow = 10
  448.     outflow = 20
  449.   else
  450.     -- adjust inflow rate based on field strength
  451.    
  452.     local field_error = (info.maxFieldStrength * (ideal_strength / 100)) - info.fieldStrength
  453.     local proportional_field_error = field_error * inflow_P_gain
  454.     inflow_I_sum = inflow_I_sum + field_error
  455.     local integral_field_error = inflow_I_sum * inflow_I_gain
  456.     local derivative_field_error = (field_error - inflow_D_last) * inflow_D_gain
  457.     inflow_D_last = field_error
  458.     local inflow_correction = proportional_field_error + integral_field_error + derivative_field_error
  459.     if inflow_correction < 0 then
  460.       inflow_I_sum = inflow_I_sum - field_error
  461.     end
  462.     inflow = inflow_correction
  463.  
  464.     if not shutting_down then
  465.  
  466.       -- adjust outflow rate based on core temperature
  467.  
  468.       local temp_error = ideal_temp - info.temperature
  469.       local proportional_temp_error = temp_error * outflow_P_gain
  470.       outflow_I_sum = outflow_I_sum + temp_error
  471.       local integral_temp_error = outflow_I_sum * outflow_I_gain
  472.       if math.abs(temp_error) < 100 then
  473.         outflow_II_sum = outflow_II_sum + integral_temp_error
  474.       else
  475.         outflow_II_sum = 0
  476.       end
  477.       local second_integral_temp_error = outflow_II_sum * outflow_II_gain
  478.       local derivative_temp_error = (temp_error - outflow_D_last) * outflow_D_gain
  479.       outflow_D_last = temp_error
  480.       local outflow_correction = proportional_temp_error + integral_temp_error + second_integral_temp_error + derivative_temp_error
  481.       if outflow_correction < 0 then
  482.         outflow_I_sum = outflow_I_sum - temp_error
  483.       end
  484.       outflow = outflow_correction
  485.  
  486.       -- cut off reactor in case of emergency
  487.  
  488.       if info.temperature > cutoff_temp then
  489.         print("Reactor Too Hot, shutting down")
  490.         outflow = 0
  491.         new_strength = 47.5
  492.         state = "Emergency Shutdown"
  493.         status = "HiTe"
  494.         reactor.stopReactor()
  495.       end
  496.       if ((info.fieldStrength / info.maxFieldStrength) * 100) < cutoff_field then
  497.         print("Reactor Field Has Failed, Failsafe Activated, Shutting Down")
  498.         outflow = 0
  499.         new_strength = 47.5
  500.         state = "Emergency Shutdown"
  501.         status = "LoFi"
  502.         reactor.stopReactor()
  503.       end
  504.       if info.maxFuelConversion > 10000 and ((1 - info.fuelConversion / info.maxFuelConversion) * 100) < 3.75 then
  505.         print("Reactor Fuel Low, Shutting Down")
  506.         cutoff_temp = 10500
  507.         ideal_temp = 8000
  508.         ideal_strength = 55
  509.         cutoff_field = 2.5
  510.         state = "Emergency Shutdown"
  511.         status = "LoFu"
  512.         reactor.stopReactor()
  513.       elseif ((1 - info.fuelConversion / info.maxFuelConversion) * 100) < 3.75 then
  514.         print("Reactor Fuel Low, Shutting Down")
  515.         cutoff_temp = 10500
  516.         ideal_temp = 8000
  517.         ideal_strength = 55
  518.         cutoff_field = 2.5
  519.         state = "Emergency Shutdown"
  520.         status = "LoFu"
  521.         reactor.stopReactor()
  522.       end
  523.     else
  524.       if info.temperature < 2000 then
  525.         state = "Cooling"
  526.       end
  527.     end
  528.   end
  529.  
  530.   if state ~= "Active" and not shutting_down then
  531.     inflow_I_sum = 0
  532.     inflow_D_last = 0
  533.     outflow_I_sum = 0
  534.     outflow_II_sum = 0
  535.     outflow_D_last = 0
  536.   end
  537.  
  538.   if inflow < 0 then
  539.     inflow = 0
  540.   end
  541.   if outflow < 0 then
  542.     outflow = 0
  543.   end
  544.  
  545.   inflow = math.floor(inflow)
  546.   outflow = math.floor(outflow)
  547.  
  548.   flux_in.setFlowOverride(inflow)
  549.   flux_out.setFlowOverride(outflow)
  550.  
  551.   -- Draw screen
  552.  
  553.   if term.isAvailable() then
  554.  
  555.     -- Draw Values
  556.  
  557.     local left_margin = 2
  558.     local spacing = 2
  559.  
  560.     local values = {
  561.       "Ideal Field Strength: " .. ideal_strength .. "%",
  562.       "Field Strength:       " .. ((info.fieldStrength / info.maxFieldStrength) * 100) .. "%",
  563.       "Energy Saturation:    " .. ((info.energySaturation / info.maxEnergySaturation) * 100) .. "%",
  564.       "Fuel Remaining:       " .. ((1 - info.fuelConversion / info.maxFuelConversion) * 100) .. "%",
  565.       "Fuel Usage Rate:      " .. info.fuelConversionRate .. " nb/t",
  566.       "Ideal Temperature:    " .. ideal_temp .. "c",
  567.       "Temperature:          " .. info.temperature .. "c",
  568.       "Energy Inflow Rate:   " .. inflow .. " RF/t",
  569.       "Energy Outflow Rate:  " .. outflow .. " RF/t",
  570.       "True Output:          " .. (outflow - inflow) .. " RF/t",
  571.       "Energy Efficiency:    " .. ((outflow / inflow) * 100) .. "%",
  572.       "                      ",
  573.       "         Debugging Values         ",
  574.       "Lowest Field:         " .. lowest_field .. "%",
  575.       "Highest Temp:         " .. highest_temp .. "c",
  576.       "Status:               " .. state .. ":" .. status
  577.     }
  578.  
  579.     term.clear()
  580.    
  581.     for i, v in ipairs(values) do
  582.       term.setCursor(left_margin, i * spacing)
  583.       term.write(v)
  584.     end
  585.  
  586.     -- Draw button values
  587.  
  588.     term.setCursor(temp_adjust_x_offset, temp_adjust_y_offset+10)
  589.     term.write("Reactor Temperature")
  590.     term.setCursor(field_adjust_x_offset+1, field_adjust_y_offset+10)
  591.     term.write("Field Strength")
  592.  
  593.     -- Draw Buttons
  594.  
  595.     gpu.setForeground(0x000000)
  596.  
  597.     for bname, button in pairs(buttons) do
  598.       if button.depressed then
  599.  
  600.         button.depressed = button.depressed - 1
  601.         if button.depressed == 0 then
  602.           button.depressed = nil
  603.         end
  604.       end
  605.       if button.condition == nil or button.condition() then
  606.         local center_color = 0xAAAAAA
  607.         local highlight_color = 0xCCCCCC
  608.         local lowlight_color = 0x808080
  609.         if button.depressed then
  610.           center_color = 0x999999
  611.           highlight_color = 0x707070
  612.           lowlight_color = 0xBBBBBB
  613.         end
  614.         gpu.setBackground(center_color)
  615.         gpu.fill(button.x, button.y, button.width, button.height, " ")
  616.         if button.width > 1 and button.height > 1 then
  617.           gpu.setBackground(lowlight_color)
  618.           gpu.fill(button.x+1, button.y+button.height-1, button.width-1, 1, " ")
  619.           gpu.fill(button.x+button.width-1, button.y, 1, button.height, " ")
  620.           gpu.setBackground(highlight_color)
  621.           gpu.fill(button.x, button.y, 1, button.height, " ")
  622.           gpu.fill(button.x, button.y, button.width, 1, " ")
  623.         end
  624.         gpu.setBackground(center_color)
  625.         term.setCursor(button.x + math.floor(button.width / 2 - #button.text / 2), button.y + math.floor(button.height / 2))
  626.         term.write(button.text)
  627.       end
  628.     end
  629.  
  630.     gpu.setBackground(0x000000)
  631.     gpu.setForeground(0xFFFFFF)
  632.   end  
  633.  
  634.   -- Wait for next tick, or manual shutdown
  635.  
  636.   local event, id, op1, op2 = event.pull(0.05)
  637.   if event == "interrupted" then
  638.     if safe then
  639.       break
  640.     end
  641.   elseif event == "touch" then
  642.    
  643.     -- Handle Button Presses
  644.  
  645.     local x = op1
  646.     local y = op2
  647.  
  648.     for bname, button in pairs(buttons) do
  649.       if (button.condition == nil or button.condition()) and x >= button.x and x <= button.x + button.width and y >= button.y and y <= button.y + button.height then
  650.         button.action()
  651.         button.depressed = 3
  652.       end
  653.     end
  654.   end
  655. end
  656.  
  657. term.clear()
Add Comment
Please, Sign In to add comment