Advertisement
Guest User

Untitled

a guest
Jul 24th, 2014
234
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --tankmon
  2. --   Tank monitoring program edited by RikuSS4
  3. --    Original program by Forgotten_Boy
  4. --    Hardware detector program by Sharidan
  5. --      Requires OpenPeripherals (OP). Tested with version 3.0.
  6. --      Supports iron & steel Railcraft tanks, Open Block tanks, Ender Tanks, AE ExtraCells tanks,
  7. --    TConstruct tanks, and Extra Utilities Drums.
  8. --      Also supports multiple tanks, and tanks attached with modems.
  9. --      If I missed any tanks, let me know. I will add it to the list.
  10. --[[
  11.  Setup:
  12.  - Place an Advanced Computer with wireless modem and with tankmon on it adjacent to a tank.  Run "tankmon".
  13.  - Setup another Advanced Computer with wireless modem and with tankmon on it adjacent to an advanced monitor and/or terminal glass bridge.  Run "tankmon".
  14.  - 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.
  15.  - 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.
  16.  
  17.  Optional Setup:
  18.  - Place an Advanced Computer with wired and wireless modems with lan cables connecting all tanks with lan modems attached to tanks and to computer.  Run "tankmon".
  19.  - Setup another Advanced Computer with wireless modem and with tankmon on it adjacent to an advanced monitor and/or terminal glass bridge.  Run "tankmon".
  20.  - Your monitor should now show the contents of the tanks.  Add as many tanks as you like and the server will simply add them to the display.
  21.  - 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.
  22.  
  23.  Advanced usage:
  24.  - 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:
  25.  tankmon 100 left
  26.  tankmon 0 top
  27.  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.
  28. --]]
  29.  
  30. -- Variable definitions
  31. local valve, monitor, screenw, screenh
  32. local serverID = nil
  33. local clients = {}
  34. local args = {...}
  35. local redLimit, redside, on
  36. local sides = {"left", "right", "top", "bottom", "front", "back"};
  37. local tankTypes = {"rcirontankvalvetile","rcsteeltankvalvetile","iron_tank_valve", "steel_tank_valve", "openblocks_tank", "drum", "ender_tank", "cofh_thermalexpansion_tank", "net_minecraft_src_buildcraft_factory_tiletank", "tileentitycertustank", "tconstruct_lavatank"};
  38. local scale = .5 --Scale for monitor text
  39. local skipEmpty = true --Skip showing empty tanks
  40. local count = 0 --Counter for tanks
  41.  
  42. ----------------------------------------------------
  43. -- Terminal Bridge Glasses Variable definitions
  44. ----------------------------------------------------
  45. local bridge = {}
  46. bridge["TankText"] = {}
  47. bridge["TankBackground"] = {}
  48. bridge["TankTexture"] = {}
  49. -------------------------------------------------------
  50. -- Terminal Bridge Glasses display variable definitions
  51. -- Feel free to alter these to your liking
  52. -------------------------------------------------------
  53. bridge["BackgroundColor"] = 0x000000 --Background Bar color
  54. bridge["TextColor"] = 0x33B5E5 --Text color
  55. bridge["TextScale"] = 1 --Text Scale
  56. bridge["ExtendBackground"] = true --Extend Black background behind text
  57. bridge["BarWidth"] = 25 --Tank bar width
  58. bridge["BarHeight"] = 50 --Tank bar height
  59. bridge["XOffset"] = 5 --X Offset for displaying info
  60. bridge["YOffset"] = 50 --Y Offset for displaying info
  61. bridge["XSpacing"] = 5 --Space between columns
  62. bridge["YSpacing"] = 5 --Space between rows
  63. bridge["Alpha"] = 1 --Alpha value of bar background
  64. bridge["LinesAmt"] = 3 --Number of text lines after tank bar
  65. bridge["MaxCols"] = 3 --Max Number of cols to display per page
  66. bridge["MaxRows"] = 3 --Max Number of rows to display per page
  67. -------------------------------------------------------
  68. -- Which row to start with. This will be changed to
  69. -- automatically change based on user input in chat
  70. -- command box.
  71. -------------------------------------------------------
  72. bridge["StartRow"] = 0 --Min Row to display
  73. -------------------------------------------------------
  74. -- Altering these does nothing
  75. -------------------------------------------------------
  76. bridge["CurrentRow"] = 1 --Current Row
  77. bridge["CurrentCol"] = 1 --Current Col
  78.  
  79. ----------------------------------------------------
  80. -- Function definitions
  81. ----------------------------------------------------
  82. local liquidNameColors = {
  83.                {"water", colors.blue, "Water" },
  84.                {"lava", colors.orange, "Lava" },
  85.                {"liquidforce", colors.yellow, "Liquid Force" },
  86.                {"turpentine", colors.brown, "Turpentine" },
  87.                {"poison", colors.purple, "Poison" },
  88.                {"latex", colors.white, "Latex" },
  89.                {"ardite.molten", colors.orange, "Molten Ardite" },
  90.                {"gold.molten", colors.yellow, "Molten Gold" },
  91.                {"blood", colors.orange, "Blood" },
  92.                {"copper.molten", colors.orange, "Molten Copper" },
  93.                {"obsidian.molten", colors.gray, "Molten Obsidian" },
  94.                {"bop.honey", colors.yellow, "Honey" },
  95.                {"sap", colors.brown, "Sap" },
  96.                {"liquidnitrogen", colors.cyan, "Liquid Nitrogen" },
  97.                {"iron.molten", colors.gray, "Molten Iron" },
  98.                {"bop.liquidpoison", colors.purple, "Liquid Poison" },
  99.                {"alumite.molten", colors.orange, "Molten Ardite" },
  100.                {"cobalt.molten", colors.cyan, "Molten Cobalt" },
  101.                {"bop.springwater", colors.blue, "Spring Water" },
  102.                {"glowstone", colors.yellow, "Energized Glowstone" },
  103.                {"resin", colors.brown, "Resin" },
  104.                {"emerald.liquid", colors.lime, "Liquified Emerald" },
  105.                {"pinkslime", colors.pink, "Pink Slime" },
  106.                {"redstone", colors.orange, "Destabilized Redstone" },
  107.                {"xpjuice", colors.lime, "Liquid XP" },
  108.                {"oil", colors.gray, "Oil" },
  109.                {"aluminum.molten", colors.lightGray, "Molten Aluminum" },
  110.                {"manyullyn.molten", colors.purple, "Molten Manyullyn" },
  111.                {"stone.seared", colors.gray, "Seared Stone" },
  112.                {"creosote", colors.green, "Creosote Oil" },
  113.                {"sludge", colors.brown, "Sludge" },
  114.                {"bioethanol", colors.lime, "Ethanol" },
  115.                {"acid", colors.lime, "Acid" },
  116.                {"biomass", colors.lime, "Biomass" },
  117.                {"immibis.liquidxp", colors.lime, "Liquid XP" },
  118.                {"electrum.molten", colors.yellow, "Molten Electrum" },
  119.                {"sewage", colors.brown, "Sewage" },
  120.                {"slime.blue", colors.cyan, "Liquid Blueslime" },
  121.                {"tin.molten", colors.lightGray, "Molten Tin" },
  122.                {"aluminumbrass.molten", colors.orange, "Molten Aluminum Brass" },
  123.                {"milk", colors.white, "Milk" },
  124.                {"fuel", colors.lime, "Fuel" },
  125.                {"biofuel", colors.green, "Biofuel" },
  126.                {"chocolatemilk", colors.brown, "Chocolate Milk" },
  127.                {"glass.molten", colors.lightGray, "Molten Glass" },
  128.                {"cryotheum", colors.cyan, "Gelid Cryotheum" },
  129.                {"pyrotheum", colors.orange, "Blazing Pyrotheum" },
  130.                {"pinkslime", colors.pink, "Pink Slime" },
  131.                {"platinum.molten", colors.cyan, "Molten Platinum" },
  132.                {"coal", colors.gray, "Liquifacted Coal" },
  133.                {"lead.molten", colors.gray, "Molten Lead" },
  134.                {"mushroomsoup", colors.brown, "Mushroom Soup" },
  135.                {"silver.molten", colors.lightGray, "Molten Silver" },
  136.                {"nickel.molten", colors.cyan, "Molten Nickel" },
  137.                {"ender", colors.green, "Resonant Ender" },
  138.                {"invar.molten", colors.lightGray, "Molten Invar" },
  139.                {"glue", colors.white, "Glue" },
  140.                {"meat", colors.pink, "Meat" },
  141.                {"steel.molten", colors.gray, "Molten Steel" },
  142.                {"bronze.molten", colors.brown, "Molten Bronze" }
  143.                }
  144.  
  145. function cls()
  146.    term.clear()
  147.    term.setCursorPos(1,1)
  148.    term.setCursorBlink(false)
  149. end
  150. function clm()
  151.    if monitor then
  152.       monitor.setBackgroundColor(colors.black)
  153.       monitor.setTextScale(scale)
  154.       monitor.clear()
  155.       monitor.setCursorPos(1,1)
  156.       monitor.setCursorBlink(false)
  157.    end
  158. end
  159. function clb()
  160.    if bridge["peripheral"] then
  161.       bridge["peripheral"].clear()
  162.    end
  163. end
  164.  
  165. function table.merge(tbl1, tbl2)
  166.    for k,v in ipairs(tbl2) do
  167.       table.insert(tbl1, v)
  168.    end
  169.    return tbl1
  170. end
  171.  
  172. function split(str, wordNum)
  173.    local splitString = {}
  174.    for tmp in str:gmatch("%w+") do
  175.       table.insert(splitString, tmp)
  176.    end
  177.    return splitString[wordNum] or ""
  178. end
  179.  
  180. local function getLiquidColor(liquid)
  181.    for c, color in pairs (liquidNameColors) do
  182.       if (liquid == color[1]) or (liquid == color[3]) then
  183.          return color[2]
  184.       end
  185.    end
  186.    return colors.white;
  187. end
  188.  
  189. local function getDeviceSide(deviceType)
  190.     for i,side in pairs(sides) do
  191.         if (peripheral.isPresent(side)) then
  192.             if (peripheral.getType(side)) == string.lower(deviceType) then
  193.                 return side;
  194.             end
  195.         end
  196.     end
  197. end
  198.  
  199. function hardwareDetector(...)
  200.   local self = {}
  201.   -- Initialize internal hardware list
  202.   self._devList = {}
  203.  
  204.   -- Internal worker function
  205.   -- Checks a boolean value and returns the
  206.   -- corresponding supplied value
  207.   local function iif(bool, resultTrue, resultFalse)
  208.     if (bool) then
  209.       return resultTrue;
  210.     else
  211.       return resultFalse;
  212.     end
  213.   end
  214.   local function split(str, pat)
  215.     local t = {}
  216.     local fpat = "(.-)" .. pat
  217.     local last_end = 1
  218.     local s, e, cap = str:find(fpat, 1)
  219.     while s do
  220.       if s ~= 1 or cap ~= "" then
  221.         table.insert(t,cap)
  222.       end
  223.       last_end = e+1
  224.       s, e, cap = str:find(fpat, last_end)
  225.     end -- while
  226.     if last_end <= #str then
  227.       cap = str:sub(last_end)
  228.       table.insert(t, cap)
  229.     end
  230.     return t
  231.   end
  232.   local function splitType(str)
  233.     local typ, adv = str, nil
  234.     local r = split(str, ":")
  235.     if (#r == 2) then
  236.       typ = r[1]
  237.       adv = r[2]
  238.     end
  239.     return typ, adv;
  240.   end
  241.   local function wrapID(value)
  242.     if (value == nil) then
  243.       return "offline"
  244.     else
  245.       return tostring(value)
  246.     end
  247.   end
  248.   local function addDevice(label, devType, remote)
  249.     local lcdt = string.lower(devType)
  250.     local adv = "n/a";
  251.     local pCall = function() end;
  252.     if (remote) then
  253.       pCall = function(label, method)
  254.         return remote.callRemote(label, method)
  255.       end;
  256.     else
  257.       pCall = function(label, method)
  258.         return peripheral.call(label, method)
  259.       end;
  260.     end
  261.     if (lcdt == "modem") then
  262.       adv = iif(pCall(label, "isWireless"), "wireless", "cable")
  263.     elseif (lcdt == "monitor") then
  264.       adv = iif(pCall(label, "isColor"), "advanced", "normal")
  265.     elseif (lcdt == "computer" or lcdt == "turtle") then
  266.       adv = tostring(wrapID(pCall(label, "getID")))
  267.     elseif (lcdt == "drive") then
  268.       if (disk.isPresent(label)) then
  269.         if (disk.hasData(label)) then
  270.           adv = "floppy";
  271.         elseif (disk.hasAudio(label)) then
  272.           adv = "music";
  273.         else
  274.           adv = "unknown";
  275.         end
  276.       else
  277.         adv = "empty"
  278.       end
  279.     end
  280.     table.insert(self._devList, {label, devType, adv});
  281.     if (lcdt == "modem" and string.lower(adv) == "cable") then
  282.       return true;
  283.     end
  284.   end
  285.  
  286.   -- Detects all connected peripherals
  287.   function self.detect()
  288.     self._devList = {};
  289.     local sides = rs.getSides();
  290.     local remoteSide = {};
  291.     for i, side in pairs(sides) do
  292.       local devType = peripheral.getType(side);
  293.       if (devType) then
  294.         if (addDevice(side, devType)) then
  295.           table.insert(remoteSide, side);
  296.         end
  297.       end -- if
  298.     end -- for-do
  299.    
  300.     if (#remoteSide > 0) then
  301.       -- There was a cable modem attached, so we need to loop through all remote peripherals too
  302.       for r = 1, #remoteSide do
  303.         local rp = peripheral.wrap(remoteSide[r]);
  304.         local lst = rp.getNamesRemote()
  305.         for r = 1, #lst do
  306.           local name = lst[r]
  307.           local devType = rp.getTypeRemote(name);
  308.           if (devType) then
  309.             addDevice(name, devType, rp);
  310.           end
  311.         end
  312.       end -- for r
  313.     end
  314.   end
  315.  
  316.   -- Returns a tuple of the first matching peripheral
  317.   function self.find(...)
  318.     local args={...}
  319.     if (#args > 0) then
  320.       local idx = 0;
  321.       for i, sideType in pairs(self._devList) do
  322.         for a = 1, #args do
  323.           local findType = args[a];
  324.           if (type(findType) == "string") then
  325.             local typ, adv = splitType(findType);
  326.             if (string.lower(typ) == string.lower(self._devList[i][2])) then
  327.               if (adv) then
  328.                 if (string.lower(adv) == string.lower(self._devList[i][3])) then
  329.                   -- We found a device of this type
  330.                   idx = i;
  331.                 end
  332.               else
  333.                 -- We found a device of this type
  334.                 idx = i;
  335.               end
  336.               if (idx > 0) then
  337.                 return tostring(self._devList[idx][1]), tostring(self._devList[idx][2]), tostring(self._devList[idx][3])
  338.               end
  339.             end
  340.           end
  341.         end
  342.       end
  343.       return nil;
  344.     else
  345.       error("No device type specified.", 0)
  346.     end
  347.   end
  348.  
  349.   -- Returns a complete list of peripherals
  350.   function self.getAll()
  351.     return self._devList;
  352.   end
  353.  
  354.   -- Returns a list of all matching peripherals
  355.   function self.getList(...)
  356.       local args={...}
  357.       local results = {}
  358.       if (#args > 0) then
  359.          for i, sideType in pairs(self._devList) do
  360.             for a = 1, #args do
  361.                local findType = args[a];
  362.                if (type(findType) == "string") then
  363.                   if (string.lower(findType) == string.lower(self._devList[i][2])) then
  364.                      -- We found a device of this type
  365.                      table.insert(results, {tostring(self._devList[i][1]), tostring(self._devList[i][2]), tostring(self._devList[i][3])})
  366.                   end
  367.                elseif (type(findType) == "table") then
  368.                   for i2, entry in pairs(findType) do
  369.                      if (type(entry) == "string") then
  370.                         if (string.lower(entry) == string.lower(self._devList[i][2])) then
  371.                            -- We found a device of this type
  372.                            table.insert(results, {tostring(self._devList[i][1]), tostring(self._devList[i][2]), tostring(self._devList[i][3])})
  373.                         end
  374.                      end
  375.                   end
  376.                end
  377.             end
  378.          end
  379.          return results;
  380.       else
  381.          error("No device type specified.", 0);
  382.       end
  383.    end
  384.  
  385.   -- Determines if the device is remote or not
  386.   function self.isRemote(dev)
  387.     if (type(dev) == "string") then
  388.       local sides = rs.getSides();
  389.       for i, s in pairs(sides) do
  390.         if (string.lower(dev) == string.lower(s)) then
  391.           return nil;
  392.         end
  393.       end
  394.       return true;
  395.     else
  396.       error("Device connect string expected.", 0);
  397.     end
  398.   end
  399.  
  400.   -- Internal calls, don't mess with these
  401.   self.detect()
  402.  
  403.   local args = {...};
  404.   if (#args > 0) then
  405.     return self.find(...);
  406.   else
  407.     -- If no parameters were passed,
  408.     -- return the hardware object
  409.     return self;
  410.   end
  411. end
  412.  
  413. local function showLevel(count,total,filled,color,label,rawLabel, amt, threshold, signal)
  414.    if (monitor) then
  415.       local screenw, screenh = monitor.getSize()
  416.       --total = total + 1
  417.       if (not screenw) then
  418.          return nil;
  419.          -- monitor has been broken
  420.       end
  421.  
  422.       local starty = screenh -  math.floor((screenh * filled))
  423.       local width  = math.ceil(screenw / total)
  424.       local offset = math.ceil((screenw / total) * (count-1))
  425.       local amtw = string.len(amt)
  426.       local thresholdy = (threshold and ( screenh - ((threshold / 100) * screenh)))
  427.    
  428.       if (count == total) then
  429.       --  the final column should use up the remaining space.  A hack!
  430.          width = screenw - offset
  431.       end
  432.  
  433.       if (thresholdy and thresholdy < 1) then
  434.          thresholdy = 1
  435.       else
  436.          if (thresholdy and thresholdy > screenh) then
  437.             thresholdy = screenh
  438.          end
  439.       end
  440.  
  441.       term.redirect(monitor)
  442.       for c=starty, screenh + 1, 1 do
  443.          for line=0, width, 1 do
  444.             paintutils.drawPixel(line + offset, c, color)
  445.          end
  446.       end
  447.       if (thresholdy) then
  448.          local thresholdColor = color
  449.          for line=0, width, 1 do
  450.             thresholdColor = color
  451.             if (signal) then
  452.                thresholdColor = colors.red
  453.             else
  454.                -- makes a dotted line when there is no redstone signal
  455.                if (line % 2 == 0) then
  456.                   thresholdColor = colors.red
  457.                else
  458.                   thresholdColor = color
  459.                end
  460.             end
  461.             paintutils.drawPixel(line + offset, thresholdy, thresholdColor)
  462.          end
  463.       end
  464.  
  465.       --truncate the label to the width of the bar.
  466.       monLabel = string.sub(rawLabel, 1, math.max((width - 1), 0))
  467.  
  468.       monitor.setBackgroundColor(color)
  469.       if (color == colors.white) then
  470.          monitor.setTextColor(colors.black)
  471.       end
  472.    
  473.       labely = math.min((starty + 1), screenh - 1)
  474.       monitor.setCursorPos(offset + 1, labely)
  475.       monitor.setTextScale(scale)
  476.       write(monLabel)
  477.    
  478.       if (amtw <= width) then
  479.          amty = math.min(labely + 1, screenh)
  480.          monitor.setCursorPos(offset + 1, amty)
  481.          write(amt)
  482.       end
  483.       monitor.setTextColor(colors.white)
  484.       term.restore()
  485.    end
  486.    if (bridge["peripheral"]) then
  487.       --Maximum length string can be
  488.       local cutoffPoint = math.ceil(bridge["BarWidth"] / (8*bridge["TextScale"]))
  489.  
  490.       bridge["CurrentRow"] = math.floor((count+bridge["MaxCols"]-1)/bridge["MaxCols"])
  491.       bridge["CurrentCol"] = ((count+bridge["MaxCols"]-1) - bridge["CurrentRow"]*bridge["MaxCols"]) + 1
  492.      
  493.       if (bridge["CurrentRow"] > bridge["StartRow"]) and (bridge["CurrentRow"] <= (bridge["StartRow"] + bridge["MaxRows"])) then
  494.          --Heigth including extra lines below tank display
  495.          local fullHeight = bridge["BarHeight"]+((8*bridge["TextScale"])*(bridge["LinesAmt"]))
  496.          --X and Y coords for tank displays
  497.          local x = bridge["XOffset"] + ((bridge["BarWidth"] + bridge["XSpacing"]) * (bridge["CurrentCol"]-1))
  498.          local y = bridge["YOffset"] + ((fullHeight+bridge["YSpacing"])*(bridge["CurrentRow"]-bridge["StartRow"]-1))
  499.          --Draw tank background using liquid texture
  500.          if bridge["ExtendBackground"] then
  501.             bridge["TankBackground"][count] = bridge["peripheral"].addBox(x,y,bridge["BarWidth"],fullHeight,bridge["BackgroundColor"],bridge["Alpha"])
  502.          else
  503.             bridge["TankBackground"][count] = bridge["peripheral"].addBox(x,y,bridge["BarWidth"],bridge["BarHeight"],bridge["BackgroundColor"],bridge["Alpha"])
  504.          end
  505.          bridge["TankTexture"][count] = bridge["peripheral"].addLiquid(x+1,y+1+math.ceil(bridge["BarHeight"]-(bridge["BarHeight"] * filled)),bridge["BarWidth"]-2,(bridge["BarHeight"] * filled)-2,label)
  506.          --Display info to bridge
  507.          bridge["TankText"][count] = bridge["TankText"][count] or {}
  508.          for i=0,(bridge["LinesAmt"]-1) do
  509.             bridge["TankText"][count][i] = bridge["peripheral"].addText((x+2), (bridge["BarHeight"]+y+((8*bridge["TextScale"])*i)),"",bridge["TextColor"])
  510.             bridge["TankText"][count][i].setScale(scale)
  511.          end
  512.          bridge["TankText"][count][0].setText(string.sub(split(rawLabel,1), 1, cutoffPoint))
  513.          bridge["TankText"][count][1].setText(string.sub(split(rawLabel,2), 1, cutoffPoint))
  514.          bridge["TankText"][count][2].setText(string.sub(tostring(math.floor(filled*100)).."%", 1, cutoffPoint))
  515.       end
  516.    end
  517. end
  518.  
  519. local function tankStats(tank)
  520.     if(tank) then
  521.       local name = tank["name"] or nil
  522.       local rawName = tank["rawName"] or nil
  523.         local amt = tank["amount"]
  524.         local size = tank["capacity"]
  525.         local filled = (amt and 1 / (size / amt)) or 0
  526.       local threshold = tank["redLimit"] or -1
  527.       local signalOn = tank["on"] or false
  528.         return name, rawName, amt, size, filled, threshold, signalOn
  529.     else
  530.         return nil;
  531.     end
  532. end
  533.  
  534. local function tableCount(t)
  535.     local total=0
  536.     for k,v in pairs (t) do
  537.         total = total + 1
  538.     end
  539.     return total
  540. end
  541.  
  542. function printTable(tt, indent)
  543.    print(tableToString(tt, indent))
  544. end
  545.  
  546. function tableToString (tt, indent, done)
  547.   done = done or {}
  548.   indent = indent or 0
  549.   if type(tt) == "table" then
  550.     local sb = {}
  551.     for key, value in pairs (tt) do
  552.       table.insert(sb, string.rep (" ", indent)) -- indent it
  553.       if type (value) == "table" and not done [value] then
  554.         done [value] = true
  555.         table.insert(sb, "{\n");
  556.         table.insert(sb, tableToString (value, indent + 2, done))
  557.         table.insert(sb, string.rep (" ", indent)) -- indent it
  558.         table.insert(sb, "}\n");
  559.       elseif "number" == type(key) then
  560.         table.insert(sb, string.format("\"%s\"\n", tostring(value)))
  561.       else
  562.         table.insert(sb, string.format("%s = \"%s\"\n", tostring (key), tostring(value)))
  563.        end
  564.     end
  565.     return table.concat(sb)
  566.   else
  567.     return tt .. "\n"
  568.   end
  569. end
  570.  
  571. function table.contains(tbl, element)
  572.   for _, value in pairs(tbl) do
  573.     if value == element then
  574.       return true
  575.     end
  576.   end
  577.   return false
  578. end
  579.  
  580. local function findTank(tbl)
  581.    if type(tbl) == "table" then
  582.       for index,value in pairs(tbl) do
  583.          if type(value) == "table" then
  584.             if value["capacity"] then
  585.                return tbl
  586.             else
  587.                return findTank(value)
  588.             end
  589.          end
  590.       end
  591.    else
  592.       return nil
  593.    end
  594. end
  595. local function findTanks(tbl)
  596.    local tblTemp = {}
  597.    if type(tbl) == "table" then
  598.       for index,value in pairs(tbl) do
  599.          if type(value) == "table" then
  600.             if value["capacity"] then
  601.                table.insert(tblTemp, value)
  602.             else
  603.                table.insert(tblTemp, findTank(value))
  604.             end
  605.          end
  606.       end
  607.    end
  608.    return tblTemp
  609. end
  610. local function updateDisplay()
  611.    --printTable(findTanks(clients))
  612. --end
  613. --local function tmp()
  614.     local count = 1
  615.    local lstTanks = {}
  616.    local total = 0
  617.  
  618.    clm()
  619.    clb()
  620.  
  621.    if tableCount(clients) > 0 then
  622.       local i = 1
  623.       for ix,client in pairs (clients) do
  624.          local tanks = findTanks(client)
  625.          table.merge(lstTanks, tanks)
  626.          if (i <= 15) then
  627.             term.setCursorPos(1,6+i)
  628.             term.clearLine()
  629.             print("Client "..i.." # of Tanks: "..tostring(#tanks))
  630.          end
  631.          i = i + 1
  632.       end
  633.       total = #lstTanks
  634.       term.setCursorPos(1,6)
  635.       term.clearLine()
  636.       print("Total # of Tanks: "..tostring(total))
  637.       for _,tankInfo in pairs (lstTanks) do
  638.             local name, rawName, amt, size, filled, threshold, signalOn = tankStats(tankInfo)
  639.             local color = getLiquidColor(rawName)
  640.             local unit = ""
  641.             local amount = math.max(amt or 0, 0)
  642.             --print("Name: "..tostring(name))
  643.             --print("Raw Name: "..tostring(rawName))
  644.             --print("color: "..tostring(color))
  645.             --print("amt: "..tostring(amt))
  646.             --print("size: "..tostring(size))
  647.             --print("filled: "..tostring(filled))
  648.    
  649.             if not (name) and (skipEmpty) then total = total - 1 end
  650.             if name or (not (name) and not (skipEmpty)) then
  651.                if (amount > 1000000) then
  652.                   unit="M"
  653.                   amount=string.format("%.2f", math.floor(amt / 1000) / 1000)
  654.                   --unit="K Buckets"
  655.                   --amount=string.format("%i", math.floor(amt / 1000) / 1000)
  656.                else
  657.                   if(amount > 0) then
  658.                      unit="K"
  659.                      amount=string.format("%.2f", amt / 1000)
  660.                      --unit=" Buckets"
  661.                      --amount=string.format("%i", amt / 1000)
  662.                   else
  663.                      amount = ""
  664.                   end
  665.                end
  666.                amount = amount..unit
  667.                showLevel(count, total, filled, color, name or "Empty", rawName or "Empty", amount, threshold, signalOn)
  668.                count = count + 1    
  669.             --end
  670.          end
  671.       end
  672.    end
  673.    return nil;
  674. end
  675.  
  676. local function broadcast ()
  677.     cls()
  678.     print("_____________ tankmon Server started __________")
  679.     print("Broadcasting that tank display is available...")
  680.     print("Hold Ctrl+T to Terminate.")
  681.     while true do
  682.         rednet.broadcast(os.getComputerID())
  683.         term.setCursorPos(1, 5)
  684.         term.clearLine()
  685.         write("Connected tankmon clients: " .. tableCount(clients))
  686.         sleep(7)
  687.     end
  688. end
  689.  
  690. local function receive()
  691.   while true do
  692.     local senderID, message, distance = rednet.receive()
  693.     if (message) then
  694.         local data = textutils.unserialize(message)
  695.         clients[senderID] = data
  696.     end
  697.   end
  698. end
  699.  
  700. local function display()
  701.     while true do
  702.       updateDisplay()
  703.       sleep(1.5)
  704.     end
  705. end
  706.  
  707. local function connect()
  708.     cls()
  709.    print("Looking for a tankmon server in range...")
  710.     while true do
  711.         local senderID, message, distance = rednet.receive()
  712.         serverID = senderID
  713.       print()
  714.       print("Connected to server " ..tostring(serverID)..".")
  715.       sleep(3)
  716.   end  
  717. end
  718.  
  719. local function publishTank()
  720.    while true do
  721.       if (serverID) then
  722.          local hw = hardwareDetector()
  723.          lstTanks = hw.getList(tankTypes)
  724.          if (type(lstTanks) == "table") then
  725.             if (#lstTanks > 0) then
  726.                local info = {}
  727.                for i, tank in pairs(lstTanks) do
  728.                   if not tank[1]["capacity"] then
  729.                      lstTanks[i][1] = peripheral.wrap(lstTanks[i][1]).getTankInfo("unknown")[1]
  730.                   end
  731.                end
  732.                cls()
  733.                print("** Sending out tank information **")
  734.                print("Number of tanks: "..#lstTanks)
  735.                for i, tank in pairs(lstTanks) do
  736.                   -- establish whether redstone signal should be sent
  737.                   local name, rawName, amt, size, filled, threshold, signalOn = tankStats(tank[1])
  738.                   on = false
  739.                   pctFilled = filled * 100
  740.                   if (filled and redLimit and redLimit==0 and filled==0) then
  741.                      on = true
  742.                   else
  743.                      if(filled and redLimit and filled <= redLimit) then
  744.                         on=true
  745.                      end
  746.                   end
  747.                   if(redside) then
  748.                      rs.setOutput(redside, on)
  749.                   end
  750.                   -- use rednet to update the server with this tank's info.
  751.                   tank[1]["redLimit"] = redLimit
  752.                   tank[1]["on"] = on
  753.                   table.insert(info, tank[1])
  754.                   if (redLimit and redside) then
  755.                      print("Redstone signal on: " .. tostring(on))
  756.                   end
  757.                   if (i <= 12) then
  758.                      term.setCursorPos(1,3 + i)
  759.                      term.clearLine()
  760.                      if tank[1]["amount"] then
  761.                         write("** Tank "..i.." contains: " .. tostring(tank[1]["amount"]).."mB of "..tostring(tank[1]["name"]))
  762.                      else
  763.                         write("** Tank "..i.." is empty.")
  764.                      end
  765.                   end
  766.                end
  767.                if (redLimit and redside) then
  768.                   print("Redstone threshold: " .. tostring(redLimit))
  769.                   print("Redstone output side: " .. tostring(redside))
  770.                end
  771.                rednet.send(serverID, textutils.serialize(info), false)
  772.             end
  773.          end
  774.         end
  775.         sleep(math.random(1,5))
  776.   end
  777. end
  778.  
  779. -------------------------------------------------------
  780. -- Hardware setup and detection
  781. -------------------------------------------------------
  782. local hw = hardwareDetector()
  783. local screenSide, _, _ = hw.find("monitor:advanced");
  784. local bridgeSide, _, _ = hw.find("openperipheral_glassesbridge");
  785. local modemSide, _, _ = hardwareDetector("modem:wireless")
  786. lstTanks = hw.getList(tankTypes)
  787.  
  788. if (modemSide) then
  789.     local modem = peripheral.wrap(modemSide)
  790. else
  791.     error("A wireless modem must be attached to this computer.")
  792. end
  793.  
  794. if (#lstTanks > 0) and (bridgeSide or screenSide) then
  795.     error("Either a screen or a tank valve can be connected, not both.")
  796. end
  797.  
  798. if (screenSide) then
  799.    monitor = peripheral.wrap(screenSide)
  800.     if(not monitor.isColor()) then
  801.         error("The attached monitor must be Advanced.  Get some gold!")
  802.     end
  803.    screenw, screenh = monitor.getSize()
  804.     clm()
  805. end
  806. if (bridgeSide) then
  807.    bridge["peripheral"] = peripheral.wrap(bridgeSide)
  808.    clb()
  809. end
  810.  
  811. ---------------------------------------
  812. --the Main
  813. ---------------------------------------
  814.  
  815. rednet.open(modemSide)
  816. if (#lstTanks > 0) then
  817.     -- client mode
  818.     redLimit = args[1]
  819.     redside = args[2]
  820.     if (redLimit and not redside) then
  821.         print("A threshold and redstone side must both be present.")
  822.         print("e.g. tankmon 100 top")
  823.         error()
  824.     end
  825.     if (redLimit) then
  826.         redLimit = tonumber(redLimit)
  827.         print("")
  828.         print("Tank will send redstone signal at or below " .. tostring(redLimit) .. "% on side " .. redside)
  829.     end
  830.     -- clear outstanding redstone signals.
  831.     for i,side in pairs(sides) do
  832.         rs.setOutput(side, false)
  833.     end
  834.    parallel.waitForAll(connect, publishTank)
  835. else
  836.     -- server mode
  837.     parallel.waitForAll(broadcast, receive, display)
  838. end
  839. rednet.close(modemSide)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement