Last active
August 29, 2015 14:17
-
-
Save bot190/4583b9a8eb906b9fb80d to your computer and use it in GitHub Desktop.
Updating tankmon to work with CC 1.73, Openperipherals 0.5.0
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--tankmon tppi fix | |
-- Edited by bot190 to support CC 1.73 and OpenPeripheralCore 0.5.0 | |
-- Tank monitoring program edited by Morphik08 | |
-- Original program by Forgotten_Boy | |
-- Hardware detector program by Sharidan | |
-- Requires OpenPeripherals (OP). Tested with version 3.0. | |
-- Supports iron & steel Railcraft tanks, Open Block tanks, Ender Tanks, AE ExtraCells tanks, | |
-- TConstruct tanks, Extra Utilities Drums, Mekanism Dynamic Tanks. | |
-- Also supports multiple tanks, and tanks attached with modems. | |
-- If I missed any tanks, let me know. I will add it to the list. | |
--[[ | |
Setup: | |
- Place an Advanced Computer with wireless modem and with tankmon on it adjacent to a tank. Run "tankmon". | |
- Setup another Advanced Computer with wireless modem and with tankmon on it adjacent to an advanced monitor and/or terminal glass bridge. Run "tankmon". | |
- 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. | |
- 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. | |
Optional Setup: | |
- 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". | |
- Setup another Advanced Computer with wireless modem and with tankmon on it adjacent to an advanced monitor and/or terminal glass bridge. Run "tankmon". | |
- 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. | |
- 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. | |
Advanced usage: | |
- 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: | |
tankmon 100 left | |
tankmon 0 top | |
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. | |
--]] | |
-- Variable definitions | |
local valve, monitor, screenw, screenh | |
local serverID = nil | |
local clients = {} | |
local args = {...} | |
local redLimit, redside, on | |
local sides = {"left", "right", "top", "bottom", "front", "back"}; | |
local tankTypes = {"tile.basicblock.dynamic_valve_name", "rcirontankvalvetile", "rcsteeltankvalvetile", "openblocks_tank", "drum", "ender_tank", "cofh_thermalexpansion_tank", "net_minecraft_src_buildcraft_factory_tiletank", "tileentitycertustank", "tconstruct_lavatank"}; | |
local scale = .5 --Scale for monitor text | |
local skipEmpty = true --Skip showing empty tanks | |
local count = 0 --Counter for tanks | |
---------------------------------------------------- | |
-- Terminal Bridge Glasses Variable definitions | |
---------------------------------------------------- | |
local bridge = {} | |
bridge["TankText"] = {} | |
bridge["TankBackground"] = {} | |
bridge["TankTexture"] = {} | |
------------------------------------------------------- | |
-- Terminal Bridge Glasses display variable definitions | |
-- Feel free to alter these to your liking | |
------------------------------------------------------- | |
bridge["BackgroundColor"] = 0x000000 --Background Bar color | |
bridge["TextColor"] = 0x33B5E5 --Text color | |
bridge["TextScale"] = 1 --Text Scale | |
bridge["ExtendBackground"] = true --Extend Black background behind text | |
bridge["BarWidth"] = 25 --Tank bar width | |
bridge["BarHeight"] = 50 --Tank bar height | |
bridge["XOffset"] = 5 --X Offset for displaying info | |
bridge["YOffset"] = 50 --Y Offset for displaying info | |
bridge["XSpacing"] = 5 --Space between columns | |
bridge["YSpacing"] = 5 --Space between rows | |
bridge["Alpha"] = 1 --Alpha value of bar background | |
bridge["LinesAmt"] = 3 --Number of text lines after tank bar | |
bridge["MaxCols"] = 3 --Max Number of cols to display per page | |
bridge["MaxRows"] = 3 --Max Number of rows to display per page | |
------------------------------------------------------- | |
-- Which row to start with. This will be changed to | |
-- automatically change based on user input in chat | |
-- command box. | |
------------------------------------------------------- | |
bridge["StartRow"] = 0 --Min Row to display | |
------------------------------------------------------- | |
-- Altering these does nothing | |
------------------------------------------------------- | |
bridge["CurrentRow"] = 1 --Current Row | |
bridge["CurrentCol"] = 1 --Current Col | |
---------------------------------------------------- | |
-- Function definitions | |
---------------------------------------------------- | |
local liquidNameColors = { | |
{"water", colors.blue, "Water" }, | |
{"lava", colors.orange, "Lava" }, | |
{"liquidforce", colors.yellow, "Liquid Force" }, | |
{"turpentine", colors.brown, "Turpentine" }, | |
{"poison", colors.purple, "Poison" }, | |
{"latex", colors.white, "Latex" }, | |
{"ardite.molten", colors.orange, "Molten Ardite" }, | |
{"gold.molten", colors.yellow, "Molten Gold" }, | |
{"blood", colors.orange, "Blood" }, | |
{"copper.molten", colors.orange, "Molten Copper" }, | |
{"obsidian.molten", colors.gray, "Molten Obsidian" }, | |
{"bop.honey", colors.yellow, "Honey" }, | |
{"sap", colors.brown, "Sap" }, | |
{"liquidnitrogen", colors.cyan, "Liquid Nitrogen" }, | |
{"iron.molten", colors.gray, "Molten Iron" }, | |
{"bop.liquidpoison", colors.purple, "Liquid Poison" }, | |
{"alumite.molten", colors.orange, "Molten Ardite" }, | |
{"cobalt.molten", colors.cyan, "Molten Cobalt" }, | |
{"bop.springwater", colors.blue, "Spring Water" }, | |
{"glowstone", colors.yellow, "Energized Glowstone" }, | |
{"resin", colors.brown, "Resin" }, | |
{"emerald.liquid", colors.lime, "Liquified Emerald" }, | |
{"pinkslime", colors.pink, "Pink Slime" }, | |
{"redstone", colors.red, "Redstone" }, | |
{"xpjuice", colors.lime, "Liquid XP" }, | |
{"oil", colors.gray, "Oil" }, | |
{"aluminum.molten", colors.lightGray, "Molten Aluminum" }, | |
{"manyullyn.molten", colors.purple, "Molten Manyullyn" }, | |
{"stone.seared", colors.gray, "Seared Stone" }, | |
{"creosote", colors.green, "Creosote Oil" }, | |
{"sludge", colors.brown, "Sludge" }, | |
{"bioethanol", colors.lime, "Ethanol" }, | |
{"acid", colors.lime, "Acid" }, | |
{"biomass", colors.lime, "Biomass" }, | |
{"immibis.liquidxp", colors.lime, "Liquid XP" }, | |
{"electrum.molten", colors.yellow, "Molten Electrum" }, | |
{"sewage", colors.brown, "Sewage" }, | |
{"slime.blue", colors.cyan, "Liquid Blueslime" }, | |
{"tin.molten", colors.lightGray, "Molten Tin" }, | |
{"aluminumbrass.molten", colors.orange, "Molten Aluminum Brass" }, | |
{"milk", colors.white, "Milk" }, | |
{"fuel", colors.lime, "Fuel" }, | |
{"biofuel", colors.green, "Biofuel" }, | |
{"chocolatemilk", colors.brown, "Chocolate Milk" }, | |
{"glass.molten", colors.lightGray, "Molten Glass" }, | |
{"cryotheum", colors.cyan, "Gelid Cryotheum" }, | |
{"pyrotheum", colors.orange, "Blazing Pyrotheum" }, | |
{"pinkslime", colors.pink, "Pink Slime" }, | |
{"platinum.molten", colors.cyan, "Molten Platinum" }, | |
{"coal", colors.gray, "Liquifacted Coal" }, | |
{"lead.molten", colors.gray, "Molten Lead" }, | |
{"mushroomsoup", colors.brown, "Mushroom Soup" }, | |
{"silver.molten", colors.lightGray, "Molten Silver" }, | |
{"nickel.molten", colors.cyan, "Molten Nickel" }, | |
{"ender", colors.green, "Resonant Ender" }, | |
{"invar.molten", colors.lightGray, "Molten Invar" }, | |
{"glue", colors.white, "Glue" }, | |
{"meat", colors.pink, "Meat" }, | |
{"steel.molten", colors.gray, "Molten Steel" }, | |
{"bronze.molten", colors.brown, "Molten Bronze" } | |
} | |
function cls() | |
term.clear() | |
term.setCursorPos(1,1) | |
term.setCursorBlink(false) | |
end | |
function clm() | |
if monitor then | |
monitor.setBackgroundColor(colors.black) | |
monitor.setTextScale(scale) | |
monitor.clear() | |
monitor.setCursorPos(1,1) | |
monitor.setCursorBlink(false) | |
end | |
end | |
function clb() | |
if bridge["peripheral"] then | |
bridge["peripheral"].clear() | |
end | |
end | |
function table.merge(tbl1, tbl2) | |
for k,v in ipairs(tbl2) do | |
table.insert(tbl1, v) | |
end | |
return tbl1 | |
end | |
function split(str, wordNum) | |
local splitString = {} | |
for tmp in str:gmatch("%w+") do | |
table.insert(splitString, tmp) | |
end | |
return splitString[wordNum] or "" | |
end | |
local function getLiquidColor(liquid) | |
for c, color in pairs (liquidNameColors) do | |
if (liquid == color[1]) or (liquid == color[3]) then | |
return color[2] | |
end | |
end | |
return colors.white; | |
end | |
local function getDeviceSide(deviceType) | |
for i,side in pairs(sides) do | |
if (peripheral.isPresent(side)) then | |
if (peripheral.getType(side)) == string.lower(deviceType) then | |
return side; | |
end | |
end | |
end | |
end | |
function hardwareDetector(...) | |
local self = {} | |
-- Initialize internal hardware list | |
self._devList = {} | |
-- Internal worker function | |
-- Checks a boolean value and returns the | |
-- corresponding supplied value | |
local function iif(bool, resultTrue, resultFalse) | |
if (bool) then | |
return resultTrue; | |
else | |
return resultFalse; | |
end | |
end | |
local function split(str, pat) | |
local t = {} | |
local fpat = "(.-)" .. pat | |
local last_end = 1 | |
local s, e, cap = str:find(fpat, 1) | |
while s do | |
if s ~= 1 or cap ~= "" then | |
table.insert(t,cap) | |
end | |
last_end = e+1 | |
s, e, cap = str:find(fpat, last_end) | |
end -- while | |
if last_end <= #str then | |
cap = str:sub(last_end) | |
table.insert(t, cap) | |
end | |
return t | |
end | |
local function splitType(str) | |
local typ, adv = str, nil | |
local r = split(str, ":") | |
if (#r == 2) then | |
typ = r[1] | |
adv = r[2] | |
end | |
return typ, adv; | |
end | |
local function wrapID(value) | |
if (value == nil) then | |
return "offline" | |
else | |
return tostring(value) | |
end | |
end | |
local function addDevice(label, devType, remote) | |
local lcdt = string.lower(devType) | |
local adv = "n/a"; | |
local pCall = function() end; | |
if (remote) then | |
pCall = function(label, method) | |
return remote.callRemote(label, method) | |
end; | |
else | |
pCall = function(label, method) | |
return peripheral.call(label, method) | |
end; | |
end | |
if (lcdt == "modem") then | |
adv = iif(pCall(label, "isWireless"), "wireless", "cable") | |
elseif (lcdt == "monitor") then | |
adv = iif(pCall(label, "isColor"), "advanced", "normal") | |
elseif (lcdt == "computer" or lcdt == "turtle") then | |
adv = tostring(wrapID(pCall(label, "getID"))) | |
elseif (lcdt == "drive") then | |
if (disk.isPresent(label)) then | |
if (disk.hasData(label)) then | |
adv = "floppy"; | |
elseif (disk.hasAudio(label)) then | |
adv = "music"; | |
else | |
adv = "unknown"; | |
end | |
else | |
adv = "empty" | |
end | |
end | |
table.insert(self._devList, {label, devType, adv}); | |
if (lcdt == "modem" and string.lower(adv) == "cable") then | |
return true; | |
end | |
end | |
-- Detects all connected peripherals | |
function self.detect() | |
self._devList = {}; | |
local sides = rs.getSides(); | |
local remoteSide = {}; | |
for i, side in pairs(sides) do | |
local devType = peripheral.getType(side); | |
if (devType) then | |
if (addDevice(side, devType)) then | |
table.insert(remoteSide, side); | |
end | |
end -- if | |
end -- for-do | |
if (#remoteSide > 0) then | |
-- There was a cable modem attached, so we need to loop through all remote peripherals too | |
for r = 1, #remoteSide do | |
local rp = peripheral.wrap(remoteSide[r]); | |
local lst = rp.getNamesRemote() | |
for r = 1, #lst do | |
local name = lst[r] | |
local devType = rp.getTypeRemote(name); | |
if (devType) then | |
addDevice(name, devType, rp); | |
end | |
end | |
end -- for r | |
end | |
end | |
-- Returns a tuple of the first matching peripheral | |
function self.find(...) | |
local args={...} | |
if (#args > 0) then | |
local idx = 0; | |
for i, sideType in pairs(self._devList) do | |
for a = 1, #args do | |
local findType = args[a]; | |
if (type(findType) == "string") then | |
local typ, adv = splitType(findType); | |
if (string.lower(typ) == string.lower(self._devList[i][2])) then | |
if (adv) then | |
if (string.lower(adv) == string.lower(self._devList[i][3])) then | |
-- We found a device of this type | |
idx = i; | |
end | |
else | |
-- We found a device of this type | |
idx = i; | |
end | |
if (idx > 0) then | |
return tostring(self._devList[idx][1]), tostring(self._devList[idx][2]), tostring(self._devList[idx][3]) | |
end | |
end | |
end | |
end | |
end | |
return nil; | |
else | |
error("No device type specified.", 0) | |
end | |
end | |
-- Returns a complete list of peripherals | |
function self.getAll() | |
return self._devList; | |
end | |
-- Returns a list of all matching peripherals | |
function self.getList(...) | |
local args={...} | |
local results = {} | |
if (#args > 0) then | |
for i, sideType in pairs(self._devList) do | |
for a = 1, #args do | |
local findType = args[a]; | |
if (type(findType) == "string") then | |
if (string.lower(findType) == string.lower(self._devList[i][2])) then | |
-- We found a device of this type | |
table.insert(results, {tostring(self._devList[i][1]), tostring(self._devList[i][2]), tostring(self._devList[i][3])}) | |
end | |
elseif (type(findType) == "table") then | |
for i2, entry in pairs(findType) do | |
if (type(entry) == "string") then | |
if (string.lower(entry) == string.lower(self._devList[i][2])) then | |
-- We found a device of this type | |
table.insert(results, {tostring(self._devList[i][1]), tostring(self._devList[i][2]), tostring(self._devList[i][3])}) | |
end | |
end | |
end | |
end | |
end | |
end | |
return results; | |
else | |
error("No device type specified.", 0); | |
end | |
end | |
-- Determines if the device is remote or not | |
function self.isRemote(dev) | |
if (type(dev) == "string") then | |
local sides = rs.getSides(); | |
for i, s in pairs(sides) do | |
if (string.lower(dev) == string.lower(s)) then | |
return nil; | |
end | |
end | |
return true; | |
else | |
error("Device connect string expected.", 0); | |
end | |
end | |
-- Internal calls, don't mess with these | |
self.detect() | |
local args = {...}; | |
if (#args > 0) then | |
return self.find(...); | |
else | |
-- If no parameters were passed, | |
-- return the hardware object | |
return self; | |
end | |
end | |
local function showLevel(count,total,filled,color,label,rawLabel, amt, threshold, signal) | |
if (monitor) then | |
local screenw, screenh = monitor.getSize() | |
--total = total + 1 | |
if (not screenw) then | |
return nil; | |
-- monitor has been broken | |
end | |
local starty = screenh - math.floor((screenh * filled)) | |
local width = math.ceil(screenw / total) | |
local offset = math.ceil((screenw / total) * (count-1)) | |
local amtw = string.len(amt) | |
local thresholdy = (threshold and ( screenh - ((threshold / 100) * screenh))) | |
if (count == total) then | |
-- the final column should use up the remaining space. A hack! | |
width = screenw - offset | |
end | |
if (thresholdy and thresholdy < 1) then | |
thresholdy = 1 | |
else | |
if (thresholdy and thresholdy > screenh) then | |
thresholdy = screenh | |
end | |
end | |
restoreTo = term.current() | |
term.redirect(monitor) | |
for c=starty, screenh + 1, 1 do | |
for line=0, width, 1 do | |
paintutils.drawPixel(line + offset, c, color) | |
end | |
end | |
if (thresholdy) then | |
local thresholdColor = color | |
for line=0, width, 1 do | |
thresholdColor = color | |
if (signal) then | |
thresholdColor = colors.red | |
else | |
-- makes a dotted line when there is no redstone signal | |
if (line % 2 == 0) then | |
thresholdColor = colors.red | |
else | |
thresholdColor = color | |
end | |
end | |
paintutils.drawPixel(line + offset, thresholdy, thresholdColor) | |
end | |
end | |
--truncate the label to the width of the bar. | |
monLabel = string.sub(rawLabel, 1, math.max((width - 1), 0)) | |
monitor.setBackgroundColor(color) | |
if (color == colors.white) then | |
monitor.setTextColor(colors.black) | |
end | |
labely = math.min((starty + 1), screenh - 1) | |
monitor.setCursorPos(offset + 1, labely) | |
monitor.setTextScale(scale) | |
write(monLabel) | |
if (amtw <= width) then | |
amty = math.min(labely + 1, screenh) | |
monitor.setCursorPos(offset + 1, amty) | |
write(amt) | |
end | |
monitor.setTextColor(colors.white) | |
term.redirect(restoreTo) | |
end | |
if (bridge["peripheral"]) then | |
--Maximum length string can be | |
local cutoffPoint = math.ceil(bridge["BarWidth"] / (8*bridge["TextScale"])) | |
bridge["CurrentRow"] = math.floor((count+bridge["MaxCols"]-1)/bridge["MaxCols"]) | |
bridge["CurrentCol"] = ((count+bridge["MaxCols"]-1) - bridge["CurrentRow"]*bridge["MaxCols"]) + 1 | |
if (bridge["CurrentRow"] > bridge["StartRow"]) and (bridge["CurrentRow"] <= (bridge["StartRow"] + bridge["MaxRows"])) then | |
--Heigth including extra lines below tank display | |
local fullHeight = bridge["BarHeight"]+((8*bridge["TextScale"])*(bridge["LinesAmt"])) | |
--X and Y coords for tank displays | |
local x = bridge["XOffset"] + ((bridge["BarWidth"] + bridge["XSpacing"]) * (bridge["CurrentCol"]-1)) | |
local y = bridge["YOffset"] + ((fullHeight+bridge["YSpacing"])*(bridge["CurrentRow"]-bridge["StartRow"]-1)) | |
--Draw tank background using liquid texture | |
if bridge["ExtendBackground"] then | |
bridge["TankBackground"][count] = bridge["peripheral"].addBox(x,y,bridge["BarWidth"],fullHeight,bridge["BackgroundColor"],bridge["Alpha"]) | |
else | |
bridge["TankBackground"][count] = bridge["peripheral"].addBox(x,y,bridge["BarWidth"],bridge["BarHeight"],bridge["BackgroundColor"],bridge["Alpha"]) | |
end | |
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) | |
--Display info to bridge | |
bridge["TankText"][count] = bridge["TankText"][count] or {} | |
for i=0,(bridge["LinesAmt"]-1) do | |
bridge["TankText"][count][i] = bridge["peripheral"].addText((x+2), (bridge["BarHeight"]+y+((8*bridge["TextScale"])*i)),"",bridge["TextColor"]) | |
bridge["TankText"][count][i].setScale(scale) | |
end | |
bridge["TankText"][count][0].setText(string.sub(split(rawLabel,1), 1, cutoffPoint)) | |
bridge["TankText"][count][1].setText(string.sub(split(rawLabel,2), 1, cutoffPoint)) | |
bridge["TankText"][count][2].setText(string.sub(tostring(math.floor(filled*100)).."%", 1, cutoffPoint)) | |
end | |
end | |
end | |
local function tankStats(tank) | |
if(tank) then | |
local name = tank["contents"]["name"] or nil | |
local rawName = tank["contents"]["rawName"] or nil | |
local amt = tank["contents"]["amount"] | |
local size = tank["capacity"] | |
local filled = (amt and 1 / (size / amt)) or 0 | |
local threshold = tank["contents"]["redLimit"] or -1 | |
local signalOn = tank["contents"]["on"] or false | |
return name, rawName, amt, size, filled, threshold, signalOn | |
else | |
return nil; | |
end | |
end | |
local function tableCount(t) | |
local total=0 | |
for k,v in pairs (t) do | |
total = total + 1 | |
end | |
return total | |
end | |
function printTable(tt, indent) | |
print(tableToString(tt, indent)) | |
end | |
function tableToString (tt, indent, done) | |
done = done or {} | |
indent = indent or 0 | |
if type(tt) == "table" then | |
local sb = {} | |
for key, value in pairs (tt) do | |
table.insert(sb, string.rep (" ", indent)) -- indent it | |
if type (value) == "table" and not done [value] then | |
done [value] = true | |
table.insert(sb, "{\n"); | |
table.insert(sb, tableToString (value, indent + 2, done)) | |
table.insert(sb, string.rep (" ", indent)) -- indent it | |
table.insert(sb, "}\n"); | |
elseif "number" == type(key) then | |
table.insert(sb, string.format("\"%s\"\n", tostring(value))) | |
else | |
table.insert(sb, string.format("%s = \"%s\"\n", tostring (key), tostring(value))) | |
end | |
end | |
return table.concat(sb) | |
else | |
return tt .. "\n" | |
end | |
end | |
function table.contains(tbl, element) | |
for _, value in pairs(tbl) do | |
if value == element then | |
return true | |
end | |
end | |
return false | |
end | |
local function findTank(tbl) | |
if type(tbl) == "table" then | |
for index,value in pairs(tbl) do | |
if type(value) == "table" then | |
if value["capacity"] then | |
return tbl | |
else | |
return findTank(value) | |
end | |
end | |
end | |
else | |
return nil | |
end | |
end | |
local function findTanks(tbl) | |
local tblTemp = {} | |
if type(tbl) == "table" then | |
for index,value in pairs(tbl) do | |
if type(value) == "table" then | |
if value["capacity"] then | |
table.insert(tblTemp, value) | |
else | |
table.insert(tblTemp, findTank(value)) | |
end | |
end | |
end | |
end | |
return tblTemp | |
end | |
local function updateDisplay() | |
--printTable(findTanks(clients)) | |
--end | |
--local function tmp() | |
local count = 1 | |
local lstTanks = {} | |
local total = 0 | |
clm() | |
clb() | |
if tableCount(clients) > 0 then | |
local i = 1 | |
for ix,client in pairs (clients) do | |
local tanks = findTanks(client) | |
table.merge(lstTanks, tanks) | |
if (i <= 15) then | |
term.setCursorPos(1,6+i) | |
term.clearLine() | |
print("Client "..i.." # of Tanks: "..tostring(#tanks)) | |
end | |
i = i + 1 | |
end | |
total = #lstTanks | |
term.setCursorPos(1,6) | |
term.clearLine() | |
print("Total # of Tanks: "..tostring(total)) | |
for _,tankInfo in pairs (lstTanks) do | |
local name, rawName, amt, size, filled, threshold, signalOn = tankStats(tankInfo) | |
local color = getLiquidColor(rawName) | |
local unit = "" | |
local amount = math.max(amt or 0, 0) | |
--print("Name: "..tostring(name)) | |
--print("Raw Name: "..tostring(rawName)) | |
--print("color: "..tostring(color)) | |
--print("amt: "..tostring(amt)) | |
--print("size: "..tostring(size)) | |
--print("filled: "..tostring(filled)) | |
if not (name) and (skipEmpty) then total = total - 1 end | |
if name or (not (name) and not (skipEmpty)) then | |
if (amount > 1000000) then | |
unit="M" | |
amount=string.format("%.2f", math.floor(amt / 1000) / 1000) | |
--unit="K Buckets" | |
--amount=string.format("%i", math.floor(amt / 1000) / 1000) | |
else | |
if(amount > 0) then | |
unit="K" | |
amount=string.format("%.2f", amt / 1000) | |
--unit=" Buckets" | |
--amount=string.format("%i", amt / 1000) | |
else | |
amount = "" | |
end | |
end | |
amount = amount..unit | |
showLevel(count, total, filled, color, name or "Empty", rawName or "Empty", amount, threshold, signalOn) | |
count = count + 1 | |
--end | |
end | |
end | |
end | |
return nil; | |
end | |
local function broadcast () | |
cls() | |
print("_____________ tankmon Server started __________") | |
print("Broadcasting that tank display is available...") | |
print("Hold Ctrl+T to Terminate.") | |
while true do | |
rednet.broadcast(os.getComputerID()) | |
term.setCursorPos(1, 5) | |
term.clearLine() | |
write("Connected tankmon clients: " .. tableCount(clients)) | |
sleep(7) | |
end | |
end | |
local function receive() | |
while true do | |
local senderID, message, distance = rednet.receive() | |
if (message) then | |
local data = textutils.unserialize(message) | |
clients[senderID] = data | |
end | |
end | |
end | |
local function display() | |
while true do | |
updateDisplay() | |
sleep(1.5) | |
end | |
end | |
local function connect() | |
cls() | |
print("Looking for a tankmon server in range...") | |
while true do | |
local senderID, message, distance = rednet.receive() | |
serverID = senderID | |
print() | |
print("Connected to server " ..tostring(serverID)..".") | |
sleep(3) | |
end | |
end | |
local function publishTank() | |
while true do | |
if (serverID) then | |
local hw = hardwareDetector() | |
lstTanks = hw.getList(tankTypes) | |
if (type(lstTanks) == "table") then | |
if (#lstTanks > 0) then | |
local info = {} | |
for i, tank in pairs(lstTanks) do | |
if not tank[1]["capacity"] then | |
lstTanks[i][1] = peripheral.wrap(lstTanks[i][1]).getTankInfo("unknown")[1] | |
end | |
end | |
cls() | |
print("** Sending out tank information **") | |
print("Number of tanks: "..#lstTanks) | |
for i, tank in pairs(lstTanks) do | |
if tank[1]["contents"] then | |
-- establish whether redstone signal should be sent | |
local name, rawName, amt, size, filled, threshold, signalOn = tankStats(tank[1]) | |
on = false | |
pctFilled = filled * 100 | |
if (filled and redLimit and redLimit==0 and filled==0) then | |
on = true | |
else | |
if(filled and redLimit and filled <= redLimit) then | |
on=true | |
end | |
end | |
if(redside) then | |
rs.setOutput(redside, on) | |
end | |
-- use rednet to update the server with this tank's info. | |
tank[1]["redLimit"] = redLimit | |
tank[1]["on"] = on | |
table.insert(info, tank[1]) | |
if (redLimit and redside) then | |
print("Redstone signal on: " .. tostring(on)) | |
end | |
if (i <= 12) then | |
term.setCursorPos(1,3 + i) | |
term.clearLine() | |
if tank[1]["contents"]["amount"] then | |
write("** Tank "..i.." contains: " .. tostring(tank[1]["contents"]["amount"]).."mB of "..tostring(tank[1]["name"])) | |
else | |
write("** Tank "..i.." is empty.") | |
end | |
end | |
end | |
end | |
if (redLimit and redside) then | |
print("Redstone threshold: " .. tostring(redLimit)) | |
print("Redstone output side: " .. tostring(redside)) | |
end | |
rednet.send(serverID, textutils.serialize(info), false) | |
end | |
end | |
end | |
sleep(math.random(1,5)) | |
end | |
end | |
------------------------------------------------------- | |
-- Hardware setup and detection | |
------------------------------------------------------- | |
local hw = hardwareDetector() | |
local screenSide, _, _ = hw.find("monitor:advanced"); | |
local bridgeSide, _, _ = hw.find("openperipheral_glassesbridge"); | |
local modemSide, _, _ = hardwareDetector("modem:wireless") | |
lstTanks = hw.getList(tankTypes) | |
if (modemSide) then | |
local modem = peripheral.wrap(modemSide) | |
else | |
error("A wireless modem must be attached to this computer.") | |
end | |
if (#lstTanks > 0) and (bridgeSide or screenSide) then | |
error("Either a screen or a tank valve can be connected, not both.") | |
end | |
if (screenSide) then | |
monitor = peripheral.wrap(screenSide) | |
if(not monitor.isColor()) then | |
error("The attached monitor must be Advanced. Get some gold!") | |
end | |
screenw, screenh = monitor.getSize() | |
clm() | |
end | |
if (bridgeSide) then | |
bridge["peripheral"] = peripheral.wrap(bridgeSide) | |
clb() | |
end | |
--------------------------------------- | |
--the Main | |
--------------------------------------- | |
rednet.open(modemSide) | |
if (#lstTanks > 0) then | |
-- client mode | |
redLimit = args[1] | |
redside = args[2] | |
if (redLimit and not redside) then | |
print("A threshold and redstone side must both be present.") | |
print("e.g. tankmon 100 top") | |
error() | |
end | |
if (redLimit) then | |
redLimit = tonumber(redLimit) | |
print("") | |
print("Tank will send redstone signal at or below " .. tostring(redLimit) .. "% on side " .. redside) | |
end | |
-- clear outstanding redstone signals. | |
for i,side in pairs(sides) do | |
rs.setOutput(side, false) | |
end | |
parallel.waitForAll(connect, publishTank) | |
else | |
-- server mode | |
parallel.waitForAll(broadcast, receive, display) | |
end | |
rednet.close(modemSide) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment