View difference between Paste ID: EnYEGdA0 and aMUgrXU6
SHOW: | | - or go back to the newest paste.
1
--tankmon
2
--   Railcraft tank monitoring by Forgotten_Boy
3
--   	requires OpenPeripherals (OP) at least version 0.1.9, supports new liquid names in OP 0.2.1
4
-- 		with thanks to AmigaLink and Kalmor for the updated liquid names.
5
--   	Supports iron and steel Railcraft tanks and 15 common liquids.
6
--[[
7
 Setup:
8
 - Place an Advanced Computer with wireless modem and with tankmon on it adjacent to a tank valve.  Run "tankmon".
9
 - Setup another Advanced Computer with wireless modem and with tankmon on it adjacent to an advanced monitor.  Run "tankmon".
10
 - Your monitor should now show the contents of the tank.  Add as many tanks as you like and the server will simply add them to the display.
11
 - The size of the monitor or locations of the modems don't matter, place them anywhere on the computer.  The monitor can be resized while tankmon is running.
12
 
13
 Advanced usage:
14
 - On the client, you can use tankmon to trigger a redstone signal when the tank reaches a certain threshold (specified as 0 to 100, a percentage).  For example:
15
 tankmon 100 left
16
 tankmon 0 top
17
 The first example will send redstone output on the left when the tank is full.  The second example will send redstone output on the top when the tank is empty.
18
--]]
19
20
-- Variable definitions
21
local valve, monitor, screenw, screenh
22
local serverID = nil
23
local clients = {}
24
local args = {...}
25
local redlimit, redside, on
26
local sides = {"left", "right", "top", "bottom", "front", "back"};
27
28
----------------------------------------------------
29
-- Function definitions
30
----------------------------------------------------
31
local liquidColors = {{"Water", colors.blue },
32
					{"tile.oilStill", colors.gray, "Oil"},
33
					{"Creosote Oil", colors.brown},
34
					{"Essence", colors.lime},
35
					{"Steam", colors.lightGray},
36
					{"Honey", colors.yellow},
37
					{"Ethanol", colors.orange},
38
					{"Lava", colors.orange},
39
					{"item.fuel", colors.yellow, "Fuel"},
40
					{"Biomass", colors.green},
41
					{"Fortron", colors.lightBlue},
42
					{"Sludge", colors.black},
43
					{"Liquid DNA", colors.magenta},
44
					{"Fruit Juice", colors.green},
45
					{"Seed Oil", colors.yellow},
46
					{"Liquid Force", colors.yellow},
47
					{"Oil", colors.gray, "Oil"},
48
					{"Fuel", colors.yellow, "Fuel"},
49
					{"uumatter", colors.purple, "UUMatter"},
50
					{"vegetable", colors.magenta, "Veg"},
51
					{"deuterium", colors.lightBlue, "Deuterium"},
52
--liquid names for OpenPeripherals 0.2.1 by AmigaLink
53
                                        {"creosote", colors.brown, "Creosote Oil"},
54
                                        {"essence", colors.lime, "Essence"},
55
                                        {"steam", colors.lightGray, "Steam"},
56
                                        {"honey", colors.yellow, "Honey"},
57
                                        {"bioethanol", colors.orange, "Ethanol"},
58
                                        {"lava", colors.orange, "Lava"},
59
                                        {"biomass", colors.green, "Biomass"},
60
                                        {"fortron", colors.lightBlue, "Fortron"},
61
                                        {"sludge", colors.black, "Sludge"},
62
                                        {"liquiddna", colors.magenta, "Liquid DNA"},
63
                                        {"fruitjuice", colors.green, "Fruit Juice"},
64
                                        {"seedoil", colors.yellow, "Seed Oil"},
65
                                        {"xpjuice", colors.lime, "XP Juice"},
66
                                        {"liquidforce", colors.yellow, "Liquid Force"},
67
                                        {"oil", colors.gray, "Oil"},
68
                                        {"fuel", colors.yellow, "Fuel"},
69-
                                        {"milk", colors.white, "Milk"},
69+
                                        {"milk", colors.white, "Milk"}
70-
-- Life Essence suggested by Fyrhtu
70+
71-
					{"life essence", colors.red, "Life Essence"}
71+
72
local function getLiquidColor(liquid)
73
  for c, color in pairs (liquidColors) do
74
	if (liquid == color[1]) then
75
		return color[2],color[3] or liquid
76
	end
77
  end
78
  return colors.white, liquid;
79
end
80
81
local function getDeviceSide(deviceType)
82
	for i,side in pairs(sides) do
83
		if (peripheral.isPresent(side)) then
84
			if (peripheral.getType(side)) == string.lower(deviceType) then
85
				return side;
86
			end
87
		end
88
	end
89
end
90
91
local function showLevel(count,max,filled,color,label, amt, threshold, signal)
92
	local screenw, screenh = monitor.getSize()
93
	max = max + 1
94
	if (not screenw) then
95
		return nil;
96
		-- monitor has been broken
97
	end
98
	
99
    local starty = screenh -  math.floor((screenh * filled))
100
    local width  = math.ceil(screenw / max + .5)
101
    local offset = math.ceil(width * (count - 1))
102
	local amtw = string.len(amt)
103
	local thresholdy = (threshold and ( screenh - ((threshold / 100) * screenh)))
104
	
105
	if (count == max) then
106
	--  the final column should use up the remaining space.  A hack!
107
		width = screenw - offset
108
	end
109
	--truncate the label to the width of the bar.
110
	label = string.sub(label, 1, math.max((width - 1), 0))
111
112
	if (thresholdy and thresholdy < 1) then
113
		thresholdy = 1
114
	else
115
		if (thresholdy and thresholdy > screenh) then
116
			thresholdy = screenh
117
		end
118
	end
119
120
    term.redirect(monitor)
121
    for c=starty, screenh + 1, 1 do
122
        for line=0, width, 1 do
123
			paintutils.drawPixel(line + offset, c, color)
124
        end
125
    end
126
	if (thresholdy) then
127
		local thresholdColor = color
128
		for line=0, width, 1 do
129
			thresholdColor = color
130
			if (signal) then
131
				thresholdColor = colors.red
132
			else
133
				-- makes a dotted line when there is no redstone signal
134
				if (line % 2 == 0) then
135
					thresholdColor = colors.red
136
				end
137
			end
138
			paintutils.drawPixel(line + offset, thresholdy, thresholdColor)
139
        end
140
	end
141
142
	monitor.setBackgroundColor(color)
143
	if (color == colors.white) then
144
		monitor.setTextColor(colors.black)
145
	end
146
	
147
	labely = math.min((starty + 1), screenh - 1)
148
	monitor.setCursorPos(offset + 1, labely)
149
	write(label)
150
	
151
	if (amtw <= width) then
152
		amty = math.min(labely + 1, screenh)
153
		monitor.setCursorPos(offset + 1, amty)
154
		write(amt)
155
	end
156
	monitor.setTextColor(colors.white)
157
    term.restore()
158
end
159-
--    term.restore()
159+
160
local function tankStats(tank)
161
	if(tank) then
162
		local amt = tank["amount"]
163
		local size = tank["capacity"]
164-
		local amt = tank["contents"]["amount"]
164+
165
		return amt, size, filled
166
	else
167
		return nil;
168
	end
169
end
170
171
local function tableCount(t)
172
	local total=0
173
	for k,v in pairs (t) do
174
		total = total + 1
175
	end
176
	return total
177
end
178
179
local function updateDisplay()
180
	local total = tableCount(clients)
181
	local count = 1
182
183
	monitor.setBackgroundColor(colors.black)
184
	monitor.setTextScale(.5)
185
	monitor.clear()
186
  
187
	for ix,client in pairs (clients) do
188
		local tank = client[1]
189
		local threshold = client[2]
190
		local signalOn = client[3]
191
		local amt,size,filled = tankStats(tank)
192
		local kind = tank["name"]
193
		local color,name = getLiquidColor(kind)
194-
		local kind = tank["contents"]["name"]
194+
195
		local amount = math.max(amt or 0, 0)
196
197
		if (amount > 1000000) then
198
			unit="M"
199
			amount=string.format("%.2f", math.floor(amt / 1000) / 1000)
200
		else
201
			if(amount > 0) then
202
			  unit="K"
203
			  amount=string.format("%.2f", amt / 1000)
204
			else
205
			  amount = ""
206
			end
207
		end
208
		amount = amount..unit
209
		showLevel(count, total, filled, color, name or "Empty", amount, threshold, signalOn)
210
		count = count + 1    
211
	end
212
	return nil;
213
end
214
215
local function broadcast ()
216
	term.clear()
217
	term.setCursorPos(1,1)
218
	print("_____________ tankmon Server started __________")
219
	print("Broadcasting that tank display is available...")
220
	print("Hold Ctrl+T to Terminate.")
221
	while true do
222
		rednet.broadcast(os.getComputerID())
223
		term.setCursorPos(1, 5)
224
		term.clearLine()
225
		write("Connected tankmon clients: " .. tostring(tableCount(clients)))
226
		sleep(7)
227
	end
228
end
229
230
local function receive()
231
  while true do
232
    local senderID, message, distance = rednet.receive()
233
    if (message) then
234
		local data = textutils.unserialize(message)
235
		clients[senderID] = data
236
    end
237
  end
238
end
239
240
local function display()
241
	while true do
242
		updateDisplay()
243
		sleep(1.5)
244
	end
245
end
246
247
local function connect()
248
	print("Looking for a tankmon server in wireless Rednet range...")
249
	while true do
250
		local senderID, message, distance = rednet.receive()
251
		serverID = senderID
252
		print("Connected to server " .. tostring(serverID))
253
		sleep(3)
254
  end  
255
end
256
257
local function publishTank()
258
    while true do
259
        if serverID then
260
			term.clear()
261
			term.setCursorPos(1,1)
262
            print("** Sending out tank information **")
263
            local tank = valve.getTanks("back")[1]
264
			-- establish whether redstone signal should be sent
265-
            local tank = valve.getTankInfo()[1]
265+
266
			on = false
267
			local filled = pctFilled * 100
268
			if (filled and redlimit and redlimit==0 and filled==0) then
269
				on = true
270
			else
271
				if(filled and redlimit and filled <= redlimit) then
272
					on=true
273
				end
274
			end
275
			if(redside) then
276
				rs.setOutput(redside, on)
277
			end
278
			-- use rednet to update the server with this tank's info.
279
			local info = {tank, redlimit, on}
280
			if (redlimit and redside) then
281
				print("Redstone threshold: " .. tostring(redlimit))
282
				print("Redstone output side: " .. redside)
283
				print("Redstone signal on: " .. tostring(on))
284
				print("")
285
			end
286
			term.clearLine()
287
			write("** Tank contains: " .. tostring(tank["amount"]))
288
            rednet.send(serverID, textutils.serialize(info), false)		
289-
			write("** Tank contains: " .. tostring(amt))
289+
290
		sleep(math.random(1,5))
291
    end
292
end
293
294
---------------------------------------
295
--the Main
296
---------------------------------------
297
local modemSide = getDeviceSide("modem");
298
299
if (modemSide) then
300
    local modem = peripheral.wrap(modemSide)
301
else
302
    error("A wireless modem must be attached to this computer.")
303
end
304
305
local tankSide = getDeviceSide("rcirontankvalvetile");
306
local tankSide2 = getDeviceSide("rcsteeltankvalvetile");
307-
local tankSide = getDeviceSide("iron_tank_valve");
307+
308-
local tankSide2 = getDeviceSide("steel_tank_valve");
308+
309-
local tankSide3 = getDeviceSide("rcsteeltankvalvetile");
309+
if ((tankSide or tankSide2) and screenSide) then
310-
local tankSide4 = getDeviceSide("rcirontankvalvetile");
310+
311-
local finalside = tankSide or tankSide2 or tankSide3 or tankSide4
311+
312
313
if (tankSide or tankSide2) then
314-
if (finalside and screenSide) then
314+
    valve = peripheral.wrap(tankSide or tankSide2)
315
end
316
if (screenSide) then
317
    monitor = peripheral.wrap(screenSide)
318-
if finalside  then
318+
319-
    valve = peripheral.wrap(finalside )
319+
320
	end
321
    screenw, screenh = monitor.getSize()
322
    monitor.clear()
323
end
324
325
rednet.open(modemSide)
326
if (valve) then
327
    -- client mode
328
	redlimit = args[1]
329
	redside = args[2]
330
	if (redlimit and not redside) then
331
		print("A threshold and redstone side must both be present.")
332
		print("e.g. tankmon 100 top")
333
		error()
334
	end
335
	if (redlimit) then
336
		redlimit = tonumber(redlimit)
337
		print("")
338
		print("Tank will send redstone signal at or below " .. tostring(redlimit) .. "% on side " .. redside)
339
	end
340
	-- clear outstanding redstone signals.
341
	for i,side in pairs(sides) do
342
		rs.setOutput(side, false)
343
	end
344
    parallel.waitForAll(connect, publishTank)
345
else
346
    -- server mode
347
    parallel.waitForAll(broadcast, receive, display)
348
end
349
rednet.close(modemSide)