Advertisement
Forgotten_Boy

tankmon - Railcraft Tank Monitoring

Oct 15th, 2013
6,592
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 11.10 KB | None | 0 0
  1. --tankmon
  2. --   Railcraft tank monitoring by 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.orange},
  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.orange, "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.red, "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, screenh)
  155.         monitor.setCursorPos(offset + 1, amty)
  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.     monitor.setBackgroundColor(colors.black)
  186.     monitor.setTextScale(.5)
  187.     monitor.clear()
  188.  
  189.     for ix,client in pairs (clients) do
  190.         local tank = client[1]
  191.         local threshold = client[2]
  192.         local signalOn = client[3]
  193.         local amt,size,filled = tankStats(tank)
  194.         local kind = tank["contents"]["name"]
  195.         local color,name = getLiquidColor(kind)
  196.         local unit = ""
  197.         local amount = math.max(amt or 0, 0)
  198.  
  199.         if (amount > 1000000) then
  200.             unit="M"
  201.             amount=string.format("%.2f", math.floor(amt / 1000) / 1000)
  202.         else
  203.             if(amount > 0) then
  204.               unit="K"
  205.               amount=string.format("%.2f", amt / 1000)
  206.             else
  207.               amount = ""
  208.             end
  209.         end
  210.         amount = amount..unit
  211.         showLevel(count, total, filled, color, name or "Empty", amount, threshold, signalOn)
  212.         count = count + 1    
  213.     end
  214.     return nil;
  215. end
  216.  
  217. local function broadcast ()
  218.     term.clear()
  219.     term.setCursorPos(1,1)
  220.     print("_____________ tankmon Server started __________")
  221.     print("Broadcasting that tank display is available...")
  222.     print("Hold Ctrl+T to Terminate.")
  223.     while true do
  224.         rednet.broadcast(os.getComputerID())
  225.         term.setCursorPos(1, 5)
  226.         term.clearLine()
  227.         write("Connected tankmon clients: " .. tostring(tableCount(clients)))
  228.         sleep(7)
  229.     end
  230. end
  231.  
  232. local function receive()
  233.   while true do
  234.     local senderID, message, distance = rednet.receive()
  235.     if (message) then
  236.         local data = textutils.unserialize(message)
  237.         clients[senderID] = data
  238.     end
  239.   end
  240. end
  241.  
  242. local function display()
  243.     while true do
  244.         updateDisplay()
  245.         sleep(1.5)
  246.     end
  247. end
  248.  
  249. local function connect()
  250.     print("Looking for a tankmon server in wireless Rednet range...")
  251.     while true do
  252.         local senderID, message, distance = rednet.receive()
  253.         serverID = senderID
  254.         print("Connected to server " .. tostring(serverID))
  255.         sleep(3)
  256.   end  
  257. end
  258.  
  259. local function publishTank()
  260.     while true do
  261.         if serverID then
  262.             term.clear()
  263.             term.setCursorPos(1,1)
  264.             print("** Sending out tank information **")
  265.             local tank = valve.getTankInfo()[1]
  266.             -- establish whether redstone signal should be sent
  267.             local amt,size,pctFilled = tankStats(tank)
  268.             on = false
  269.             local filled = pctFilled * 100
  270.             if (filled and redlimit and redlimit==0 and filled==0) then
  271.                 on = true
  272.             else
  273.                 if(filled and redlimit and filled <= redlimit) then
  274.                     on=true
  275.                 end
  276.             end
  277.             if(redside) then
  278.                 rs.setOutput(redside, on)
  279.             end
  280.             -- use rednet to update the server with this tank's info.
  281.             local info = {tank, redlimit, on}
  282.             if (redlimit and redside) then
  283.                 print("Redstone threshold: " .. tostring(redlimit))
  284.                 print("Redstone output side: " .. redside)
  285.                 print("Redstone signal on: " .. tostring(on))
  286.                 print("")
  287.             end
  288.             term.clearLine()
  289.             write("** Tank contains: " .. tostring(amt))
  290.             rednet.send(serverID, textutils.serialize(info), false)    
  291.         end
  292.         sleep(math.random(1,5))
  293.     end
  294. end
  295.  
  296. ---------------------------------------
  297. --the Main
  298. ---------------------------------------
  299. local modemSide = getDeviceSide("modem");
  300.  
  301. if (modemSide) then
  302.     local modem = peripheral.wrap(modemSide)
  303. else
  304.     error("A wireless modem must be attached to this computer.")
  305. end
  306.  
  307. local tankSide = getDeviceSide("iron_tank_valve");
  308. local tankSide2 = getDeviceSide("steel_tank_valve");
  309. local tankSide3 = getDeviceSide("rcsteeltankvalvetile");
  310. local tankSide4 = getDeviceSide("rcirontankvalvetile");
  311. local finalside = tankSide or tankSide2 or tankSide3 or tankSide4
  312. local screenSide = getDeviceSide("monitor");
  313.  
  314. if (finalside and screenSide) then
  315.     error("Either a screen or a tank valve can be connected, not both.")
  316. end
  317.  
  318. if finalside  then
  319.     valve = peripheral.wrap(finalside )
  320. end
  321.  
  322. if (screenSide) then
  323.     monitor = peripheral.wrap(screenSide)
  324.     if(not monitor.isColor()) then
  325.         error("The attached monitor must be Advanced.  Get some gold!")
  326.     end
  327.     screenw, screenh = monitor.getSize()
  328.     monitor.clear()
  329. end
  330.  
  331. rednet.open(modemSide)
  332. if (valve) then
  333.     -- client mode
  334.     redlimit = args[1]
  335.     redside = args[2]
  336.     if (redlimit and not redside) then
  337.         print("A threshold and redstone side must both be present.")
  338.         print("e.g. tankmon 100 top")
  339.         error()
  340.     end
  341.     if (redlimit) then
  342.         redlimit = tonumber(redlimit)
  343.         print("")
  344.         print("Tank will send redstone signal at or below " .. tostring(redlimit) .. "% on side " .. redside)
  345.     end
  346.     -- clear outstanding redstone signals.
  347.     for i,side in pairs(sides) do
  348.         rs.setOutput(side, false)
  349.     end
  350.     parallel.waitForAll(connect, publishTank)
  351. else
  352.     -- server mode
  353.     parallel.waitForAll(broadcast, receive, display)
  354. end
  355. rednet.close(modemSide)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement