Advertisement
Guest User

tankmon

a guest
Jan 24th, 2015
205
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.84 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.                     {"mobessence", 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.                 }
  71.  
  72. local function getLiquidColor(liquid)
  73.   for c, color in pairs (liquidColors) do
  74.     if (liquid == color[1]) then
  75.         return color[2],color[3] or liquid
  76.     end
  77.   end
  78.   return colors.white, liquid;
  79. end
  80.  
  81. local function getDeviceSide(deviceType)
  82.     for i,side in pairs(sides) do
  83.         if (peripheral.isPresent(side)) then
  84.             if (peripheral.getType(side)) == string.lower(deviceType) then
  85.                 return side;
  86.             end
  87.         end
  88.     end
  89. end
  90.  
  91. local function showLevel(count,max,filled,color,label, amt, threshold, signal)
  92.     local screenw, screenh = monitor.getSize()
  93.     max = max + 1
  94.     if (not screenw) then
  95.         return nil;
  96.         -- monitor has been broken
  97.     end
  98.    
  99.     local starty = screenh -  math.floor((screenh * filled))
  100.     local width  = math.ceil(screenw / max + .5)
  101.     local offset = math.ceil(width * (count - 1))
  102.     local amtw = string.len(amt)
  103.     local thresholdy = (threshold and ( screenh - ((threshold / 100) * screenh)))
  104.    
  105.     if (count == max) then
  106.     --  the final column should use up the remaining space.  A hack!
  107.         width = screenw - offset
  108.     end
  109.     --truncate the label to the width of the bar.
  110.     label = string.sub(label, 1, math.max((width - 1), 0))
  111.  
  112.     if (thresholdy and thresholdy < 1) then
  113.         thresholdy = 1
  114.     else
  115.         if (thresholdy and thresholdy > screenh) then
  116.             thresholdy = screenh
  117.         end
  118.     end
  119.  
  120.     term.redirect(monitor)
  121.     for c=starty, screenh + 1, 1 do
  122.         for line=0, width, 1 do
  123.             paintutils.drawPixel(line + offset, c, color)
  124.         end
  125.     end
  126.     if (thresholdy) then
  127.         local thresholdColor = color
  128.         for line=0, width, 1 do
  129.             thresholdColor = color
  130.             if (signal) then
  131.                 thresholdColor = colors.red
  132.             else
  133.                 -- makes a dotted line when there is no redstone signal
  134.                 if (line % 2 == 0) then
  135.                     thresholdColor = colors.red
  136.                 end
  137.             end
  138.             paintutils.drawPixel(line + offset, thresholdy, thresholdColor)
  139.         end
  140.     end
  141.  
  142.     monitor.setBackgroundColor(color)
  143.     if (color == colors.white) then
  144.         monitor.setTextColor(colors.black)
  145.     end
  146.    
  147.     labely = math.min((starty + 1), screenh - 1)
  148.     monitor.setCursorPos(offset + 1, labely)
  149.     write(label)
  150.    
  151.     if (amtw <= width) then
  152.         amty = math.min(labely + 1, screenh)
  153.         monitor.setCursorPos(offset + 1, amty)
  154.         write(amt)
  155.     end
  156.     monitor.setTextColor(colors.white)
  157. end
  158.  
  159. local function tankStats(tank)
  160.     if(tank) then
  161.         local amt = tank["amount"]
  162.         local size = tank["capacity"]
  163.         local filled = (amt and 1 / (size / amt)) or 0
  164.         return amt, size, filled
  165.     else
  166.         return nil;
  167.     end
  168. end
  169.  
  170. local function tableCount(t)
  171.     local total=0
  172.     for k,v in pairs (t) do
  173.         total = total + 1
  174.     end
  175.     return total
  176. end
  177.  
  178. local function updateDisplay()
  179.     local total = tableCount(clients)
  180.     local count = 1
  181.  
  182.     monitor.setBackgroundColor(colors.black)
  183.     monitor.setTextScale(.5)
  184.     monitor.clear()
  185.  
  186.     for ix,client in pairs (clients) do
  187.         local tank = client[1]
  188.         local threshold = client[2]
  189.         local signalOn = client[3]
  190.         local amt,size,filled = tankStats(tank)
  191.         local kind = tank["name"]
  192.         local color,name = getLiquidColor(kind)
  193.         local unit = ""
  194.         local amount = math.max(amt or 0, 0)
  195.  
  196.         if (amount > 1000000) then
  197.             unit="M"
  198.             amount=string.format("%.2f", math.floor(amt / 1000) / 1000)
  199.         else
  200.             if(amount > 0) then
  201.               unit="K"
  202.               amount=string.format("%.2f", amt / 1000)
  203.             else
  204.               amount = ""
  205.             end
  206.         end
  207.         amount = amount..unit
  208.         showLevel(count, total, filled, color, name or "Empty", amount, threshold, signalOn)
  209.         count = count + 1    
  210.     end
  211.     return nil;
  212. end
  213.  
  214. local function broadcast ()
  215.     term.clear()
  216.     term.setCursorPos(1,1)
  217.     print("_____________ tankmon Server started __________")
  218.     print("Broadcasting that tank display is available...")
  219.     print("Hold Ctrl+T to Terminate.")
  220.     while true do
  221.         rednet.broadcast(os.getComputerID())
  222.         term.setCursorPos(1, 5)
  223.         term.clearLine()
  224.         write("Connected tankmon clients: " .. tostring(tableCount(clients)))
  225.         sleep(7)
  226.     end
  227. end
  228.  
  229. local function receive()
  230.   while true do
  231.     local senderID, message, distance = rednet.receive()
  232.     if (message) then
  233.         local data = textutils.unserialize(message)
  234.         clients[senderID] = data
  235.     end
  236.   end
  237. end
  238.  
  239. local function display()
  240.     while true do
  241.         updateDisplay()
  242.         sleep(1.5)
  243.     end
  244. end
  245.  
  246. local function connect()
  247.     print("Looking for a tankmon server in wireless Rednet range...")
  248.     while true do
  249.         local senderID, message, distance = rednet.receive()
  250.         serverID = senderID
  251.         print("Connected to server " .. tostring(serverID))
  252.         sleep(3)
  253.   end  
  254. end
  255.  
  256. local function publishTank()
  257.     while true do
  258.         if serverID then
  259.             term.clear()
  260.             term.setCursorPos(1,1)
  261.             print("** Sending out tank information **")
  262.             local tank = valve.getTanks("back")[1]
  263.             -- establish whether redstone signal should be sent
  264.             local amt,size,pctFilled = tankStats(tank)
  265.             on = false
  266.             local filled = pctFilled * 100
  267.             if (filled and redlimit and redlimit==0 and filled==0) then
  268.                 on = true
  269.             else
  270.                 if(filled and redlimit and filled <= redlimit) then
  271.                     on=true
  272.                 end
  273.             end
  274.             if(redside) then
  275.                 rs.setOutput(redside, on)
  276.             end
  277.             -- use rednet to update the server with this tank's info.
  278.             local info = {tank, redlimit, on}
  279.             if (redlimit and redside) then
  280.                 print("Redstone threshold: " .. tostring(redlimit))
  281.                 print("Redstone output side: " .. redside)
  282.                 print("Redstone signal on: " .. tostring(on))
  283.                 print("")
  284.             end
  285.             term.clearLine()
  286.             write("** Tank contains: " .. tostring(tank["amount"]))
  287.             rednet.send(serverID, textutils.serialize(info), false)    
  288.         end
  289.         sleep(math.random(1,5))
  290.     end
  291. end
  292.  
  293. ---------------------------------------
  294. --the Main
  295. ---------------------------------------
  296. local modemSide = getDeviceSide("modem");
  297.  
  298. if (modemSide) then
  299.     local modem = peripheral.wrap(modemSide)
  300. else
  301.     error("A wireless modem must be attached to this computer.")
  302. end
  303.  
  304. local tankSide = getDeviceSide("iron_tank_valve");
  305. local tankSide2 = getDeviceSide("steel_tank_valve");
  306. local screenSide = getDeviceSide("monitor");
  307.  
  308. if ((tankSide or tankSide2) and screenSide) then
  309.     error("Either a screen or a tank valve can be connected, not both.")
  310. end
  311.  
  312. if (tankSide or tankSide2) then
  313.     valve = peripheral.wrap(tankSide or tankSide2)
  314. end
  315. if (screenSide) then
  316.     monitor = peripheral.wrap(screenSide)
  317.     if(not monitor.isColor()) then
  318.         error("The attached monitor must be Advanced.  Get some gold!")
  319.     end
  320.     screenw, screenh = monitor.getSize()
  321.     monitor.clear()
  322. end
  323.  
  324. rednet.open(modemSide)
  325. if (valve) then
  326.     -- client mode
  327.     redlimit = args[1]
  328.     redside = args[2]
  329.     if (redlimit and not redside) then
  330.         print("A threshold and redstone side must both be present.")
  331.         print("e.g. tankmon 100 top")
  332.         error()
  333.     end
  334.     if (redlimit) then
  335.         redlimit = tonumber(redlimit)
  336.         print("")
  337.         print("Tank will send redstone signal at or below " .. tostring(redlimit) .. "% on side " .. redside)
  338.     end
  339.     -- clear outstanding redstone signals.
  340.     for i,side in pairs(sides) do
  341.         rs.setOutput(side, false)
  342.     end
  343.     parallel.waitForAll(connect, publishTank)
  344. else
  345.     -- server mode
  346.     parallel.waitForAll(broadcast, receive, display)
  347. end
  348. rednet.close(modemSide)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement