Advertisement
mcfeuersturm

TankControl

Jun 19th, 2018
394
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 14.22 KB | None | 0 0
  1. --TankControl
  2. --   Railcraft tank monitoring by mcfeuersturm credits to Forgotten_Boy
  3. --      requires OpenPeripherals (OP) at least version 0.1.9, supports new liquid names in OP 0.2.1
  4. --              with thanks to AmigaLink and Kalmor for the updated liquid names.
  5. --      Supports iron and steel Railcraft tanks and 15 common liquids.
  6. --[[
  7.  Setup:
  8.  - Place an Advanced Computer with wireless modem and with tankmon on it adjacent to a tank valve.  Run "tankmon".
  9.  - Setup another Advanced Computer with wireless modem and with tankmon on it adjacent to an advanced monitor.  Run "tankmon".
  10.  - Your monitor should now show the contents of the tank.  Add as many tanks as you like and the server will simply add them to the display.
  11.  - The size of the monitor or locations of the modems don't matter, place them anywhere on the computer.  The monitor can be resized while tankmon is running.
  12.  
  13.  Advanced usage:
  14.  - On the client, you can use tankmon to trigger a redstone signal when the tank reaches a certain threshold (specified as 0 to 100, a percentage).  For example:
  15.  tankmon 100 left
  16.  tankmon 0 top
  17.  The first example will send redstone output on the left when the tank is full.  The second example will send redstone output on the top when the tank is empty.
  18. --]]
  19.  
  20. -- Variable definitions
  21. local valve, monitor, screenw, screenh
  22. local serverID = nil
  23. local clients = {}
  24. local args = {...}
  25. local redlimit, redside, on
  26. local sides = {"left", "right", "top", "bottom", "front", "back"};
  27.  
  28. ----------------------------------------------------
  29. -- Function definitions
  30. ----------------------------------------------------
  31. local liquidColors = {{"Water", colors.blue },
  32.                                         {"tile.oilStill", colors.gray, "Oil"},
  33.                                         {"Creosote Oil", colors.brown},
  34.                                         {"Essence", colors.lime},
  35.                                         {"Steam", colors.lightGray},
  36.                                         {"Honey", colors.yellow},
  37.                                         {"Ethanol", colors.orange},
  38.                                         {"Lava", colors.red},
  39.                                         {"item.fuel", colors.yellow, "Fuel"},
  40.                                         {"Biomass", colors.green},
  41.                                         {"Fortron", colors.lightBlue},
  42.                                         {"Sludge", colors.black},
  43.                                         {"Liquid DNA", colors.magenta},
  44.                                         {"Fruit Juice", colors.green},
  45.                                         {"Seed Oil", colors.yellow},
  46.                                         {"Liquid Force", colors.yellow},
  47.                                         {"Oil", colors.gray, "Oil"},
  48.                                         {"Fuel", colors.yellow, "Fuel"},
  49.                                         {"uumatter", colors.purple, "UUMatter"},
  50.                                         {"vegetable", colors.magenta, "Veg"},
  51.                                         {"deuterium", colors.lightBlue, "Deuterium"},
  52. --liquid names for OpenPeripherals 0.2.1 by AmigaLink
  53.                                         {"creosote", colors.brown, "Creosote Oil"},
  54.                                         {"essence", colors.lime, "Essence"},
  55.                                         {"steam", colors.lightGray, "Steam"},
  56.                                         {"honey", colors.yellow, "Honey"},
  57.                                         {"bioethanol", colors.orange, "Ethanol"},
  58.                                         {"lava", colors.red, "Lava"},
  59.                                         {"biomass", colors.green, "Biomass"},
  60.                                         {"fortron", colors.lightBlue, "Fortron"},
  61.                                         {"sludge", colors.black, "Sludge"},
  62.                                         {"liquiddna", colors.magenta, "Liquid DNA"},
  63.                                         {"fruitjuice", colors.green, "Fruit Juice"},
  64.                                         {"seedoil", colors.yellow, "Seed Oil"},
  65.                                         {"xpjuice", colors.lime, "XP Juice"},
  66.                                         {"liquidforce", colors.yellow, "Liquid Force"},
  67.                                         {"oil", colors.gray, "Oil"},
  68.                                         {"fuel", colors.yellow, "Fuel"},
  69.                                         {"milk", colors.white, "Milk"},
  70. -- Life Essence suggested by Fyrhtu
  71.                                         {"life essence", colors.orange, "Life Essence"}
  72.                 }
  73.  
  74. local function getLiquidColor(liquid)
  75.   for c, color in pairs (liquidColors) do
  76.         if (liquid == color[1]) then
  77.                 return color[2],color[3] or liquid
  78.         end
  79.   end
  80.   return colors.white, liquid;
  81. end
  82.  
  83. local function getDeviceSide(deviceType)
  84.         for i,side in pairs(sides) do
  85.                 if (peripheral.isPresent(side)) then
  86.                         if (peripheral.getType(side)) == string.lower(deviceType) then
  87.                                 return side;
  88.                         end
  89.                 end
  90.         end
  91. end
  92.  
  93. local function showLevel(count,max,filled,color,label, amt, threshold, signal)
  94.         local screenw, screenh = monitor.getSize()
  95.         max = max + 1
  96.         if (not screenw) then
  97.                 return nil;
  98.                 -- monitor has been broken
  99.         end
  100.        
  101.     local starty = screenh -  math.floor((screenh * filled))
  102.     local width  = math.ceil(screenw / max + .5)
  103.     local offset = math.ceil(width * (count - 1))
  104.         local amtw = string.len(amt)
  105.         local thresholdy = (threshold and ( screenh - ((threshold / 100) * screenh)))
  106.        
  107.         if (count == max) then
  108.         --  the final column should use up the remaining space.  A hack!
  109.                 width = screenw - offset
  110.         end
  111.         --truncate the label to the width of the bar.
  112.         label = string.sub(label, 1, math.max((width - 1), 0))
  113.  
  114.         if (thresholdy and thresholdy < 1) then
  115.                 thresholdy = 1
  116.         else
  117.                 if (thresholdy and thresholdy > screenh) then
  118.                         thresholdy = screenh
  119.                 end
  120.         end
  121.  
  122.     term.redirect(monitor)
  123.     for c=starty, screenh + 1, 1 do
  124.         for line=0, width, 1 do
  125.                         paintutils.drawPixel(line + offset, c, color)
  126.         end
  127.     end
  128.         if (thresholdy) then
  129.                 local thresholdColor = color
  130.                 for line=0, width, 1 do
  131.                         thresholdColor = color
  132.                         if (signal) then
  133.                                 thresholdColor = colors.red
  134.                         else
  135.                                 -- makes a dotted line when there is no redstone signal
  136.                                 if (line % 2 == 0) then
  137.                                         thresholdColor = colors.red
  138.                                 end
  139.                         end
  140.                         paintutils.drawPixel(line + offset, thresholdy, thresholdColor)
  141.         end
  142.         end
  143.  
  144.         monitor.setBackgroundColor(color)
  145.         if (color == colors.white) then
  146.                 monitor.setTextColor(colors.black)
  147.         end
  148.        
  149.         labely = math.min((starty + 1), screenh - 1)
  150.         monitor.setCursorPos(offset + 1, labely)
  151.         write(label)
  152.        
  153.         if (amtw <= width) then
  154.                 amty = math.min(labely + 1,1)
  155.                 monitor.setCursorPos(1,2)
  156.                 write(amt)
  157.         end
  158.         monitor.setTextColor(colors.white)
  159. --    term.restore()
  160. end
  161.  
  162. local function tankStats(tank)
  163.         if(tank) then
  164.                 local amt = tank["contents"]["amount"]
  165.                 local size = tank["capacity"]
  166.                 local filled = (amt and 1 / (size / amt)) or 0
  167.                 return amt, size, filled
  168.         else
  169.                 return nil;
  170.         end
  171. end
  172.  
  173. local function tableCount(t)
  174.         local total=0
  175.         for k,v in pairs (t) do
  176.                 total = total + 1
  177.         end
  178.         return total
  179. end
  180.  
  181. local function updateDisplay()
  182.         local total = tableCount(clients)
  183.         local count = 1
  184.  
  185.         term.setCursorPos(1,2)
  186.         monitor.setCursorPos(1,2)
  187.         monitor.setBackgroundColor(colors.black)
  188.         monitor.setTextScale(2)
  189.         monitor.clear()
  190.  
  191.         for ix,client in pairs (clients) do
  192.                 local tank = client[1]
  193.                 local threshold = client[2]
  194.                 local signalOn = client[3]
  195.                 local amt,size,filled = tankStats(tank)
  196.                 local kind = tank["contents"]["name"]
  197.                 local color,name = getLiquidColor(kind)
  198.                 local unit = ""
  199.                 local amount = math.max(amt or 0, 0)
  200.  
  201.                 if (amount > 1000000) then
  202.                         unit="M"
  203.                         amount=string.format("%.2f", math.floor(amt / 1000) / 1000)
  204.                 else
  205.                         if(amount > 0) then
  206.                           unit="K"
  207.                           amount=string.format("%.2f", amt / 1000)
  208.                         else
  209.                           amount = ""
  210.                         end
  211.                 end
  212.                 amount = amount..unit
  213.                 showLevel(count, total, filled, color, name or "Empty", amount, threshold, signalOn)
  214.                 count = count + 1    
  215.         end
  216.         return nil;
  217. end
  218.  
  219. local function broadcast ()
  220.         term.clear()
  221.         term.setCursorPos(1,1)
  222.         print("_____________ TankControl Server started __________")
  223.         print("Broadcasting that tank display is available...")
  224.         print("Hold Ctrl+T to Terminate.")
  225.         while true do
  226.                 rednet.broadcast(os.getComputerID())
  227.                 term.setCursorPos(1, 1)
  228.                 term.clearLine()
  229.                 sleep(7)
  230.         end
  231. end
  232.  
  233. local function receive()
  234.   while true do
  235.     local senderID, message, distance = rednet.receive()
  236.     if (message) then
  237.                 local data = textutils.unserialize(message)
  238.                 clients[senderID] = data
  239.     end
  240.   end
  241. end
  242.  
  243. local function display()
  244.         while true do
  245.                 updateDisplay()
  246.                 sleep(1.5)
  247.         end
  248. end
  249.  
  250. local function connect()
  251.         print("Looking for a tankmon server in wireless Rednet range...")
  252.         while true do
  253.                 local senderID, message, distance = rednet.receive()
  254.                 serverID = senderID
  255.                 print("Connected to server " .. tostring(serverID))
  256.                 sleep(3)
  257.   end  
  258. end
  259.  
  260. local function publishTank()
  261.     while true do
  262.         if serverID then
  263.                         term.clear()
  264.                         term.setCursorPos(1,1)
  265.             print("** Sending out tank information **")
  266.             local tank = valve.getTankInfo()[1]
  267.                         -- establish whether redstone signal should be sent
  268.                         local amt,size,pctFilled = tankStats(tank)
  269.                         on = false
  270.                         local filled = pctFilled * 100
  271.                         if (filled and redlimit and redlimit==0 and filled==0) then
  272.                                 on = true
  273.                         else
  274.                                 if(filled and redlimit and filled <= redlimit) then
  275.                                         on=true
  276.                                 end
  277.                         end
  278.                         if(redside) then
  279.                                 rs.setOutput(redside, on)
  280.                         end
  281.                         -- use rednet to update the server with this tank's info.
  282.                         local info = {tank, redlimit, on}
  283.                         if (redlimit and redside) then
  284.                                 print("Redstone threshold: " .. tostring(redlimit))
  285.                                 print("Redstone output side: " .. redside)
  286.                                 print("Redstone signal on: " .. tostring(on))
  287.                                 print("")
  288.                         end
  289.                         term.clearLine()
  290.                         write("** Tank contains: " .. tostring(amt))
  291.             rednet.send(serverID, textutils.serialize(info), false)            
  292.                 end
  293.                 sleep(math.random(1,5))
  294.     end
  295. end
  296.  
  297. ---------------------------------------
  298. --the Main
  299. ---------------------------------------
  300. local modemSide = getDeviceSide("modem");
  301.  
  302. if (modemSide) then
  303.     local modem = peripheral.wrap(modemSide)
  304. else
  305.     error("A wireless modem must be attached to this computer.")
  306. end
  307.  
  308. local tankSide = getDeviceSide("iron_tank_valve");
  309. local tankSide2 = getDeviceSide("steel_tank_valve");
  310. local tankSide3 = getDeviceSide("rcsteeltankvalvetile");
  311. local tankSide4 = getDeviceSide("rcirontankvalvetile");
  312. local finalside = tankSide or tankSide2 or tankSide3 or tankSide4
  313. local screenSide = getDeviceSide("monitor");
  314.  
  315. if (finalside and screenSide) then
  316.     error("Either a screen or a tank valve can be connected, not both.")
  317. end
  318.  
  319. if finalside  then
  320.     valve = peripheral.wrap(finalside )
  321. end
  322.  
  323. if (screenSide) then
  324.     monitor = peripheral.wrap(screenSide)
  325.         if(not monitor.isColor()) then
  326.                 error("The attached monitor must be Advanced.  Get some gold!")
  327.         end
  328.     screenw, screenh = monitor.getSize()
  329.     monitor.clear()
  330. end
  331.  
  332. rednet.open(modemSide)
  333. if (valve) then
  334.     -- client mode
  335.         redlimit = args[1]
  336.         redside = args[2]
  337.         if (redlimit and not redside) then
  338.                 print("A threshold and redstone side must both be present.")
  339.                 print("e.g. tankmon 100 top")
  340.                 error()
  341.         end
  342.         if (redlimit) then
  343.                 redlimit = tonumber(redlimit)
  344.                 print("")
  345.                 print("Tank will send redstone signal at or below " .. tostring(redlimit) .. "% on side " .. redside)
  346.         end
  347.         -- clear outstanding redstone signals.
  348.         for i,side in pairs(sides) do
  349.                 rs.setOutput(side, false)
  350.         end
  351.     parallel.waitForAll(connect, publishTank)
  352. else
  353.  
  354.     parallel.waitForAll(broadcast, receive, display)
  355. end
  356. rednet.close(modemSide)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement