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