View difference between Paste ID: MhL8hKYN and 2sFnqt01
SHOW: | | - or go back to the newest paste.
1
-- config
2
local dataCorrection = 2.5 -- value to divide IM data by.
3-
local displayMinMax = true -- set to false to hide the "MIN" and "MAX" text.
3+
local displayMinMax = false-- set to false to hide the "MIN" and "MAX" text.
4
local screenRefreshRate = 1 -- how often to display new data in seconds.
5
local unitFormatCaps = true -- true = X.X KRF. false = X.XkRF
6
local showTooltips = true -- suggests adding providers when input/output is maxed.
7
local alarmPercent = 5 -- what % to output a redstone signal. 0 to 100 to enable. -1 to disable.
8
9
--Setup
10
mon = peripheral.find("monitor")
11
mat = peripheral.find("inductionPort")
12
term.clear()
13
term.setCursorPos(1,1)
14
15
--Draw Function
16
function draw(xmin, xmax, ymin, ymax, c)
17
    mon.setBackgroundColor(c)
18
    mon.setCursorPos(xmin, ymin)
19
    if xmax ~= 1 then
20
        for i = 1, xmax, 1 do
21
            mon.write(" ")
22
            mon.setCursorPos(xmin+i, ymin)
23
        end
24
    end
25
    if ymax ~= 1 then
26
        for k = 1, ymax, 1 do
27
            mon.write(" ")
28
            mon.setCursorPos(xmin, ymin+k)
29
        end
30
    end
31
    mon.setBackgroundColor(32768)
32
end
33
34
--DrawBar Function
35
function drawBar(xmin, xmax, y, r, c)
36
    for i=1, r, 1 do    
37
        draw(xmin, xmax, y+i-1, 1, c)
38
    end
39
end
40
41
-- error screen
42
function displayError(index)
43
    local x, y = mon.getSize()
44
    if x ~= 50 or y ~= 19 then return end
45
46
    local errorText = "ERROR"
47
    local errors = {
48
        "The Induction Matrix has been tampered with.",
49
        "Induction Port not connected.",
50
        "The Induction Matrix is incomplete."
51
    }
52
53
    mon.clear()
54
    -- error
55
    mon.setTextColour(16384)
56
    mon.setCursorPos((x/2) - (string.len(errorText)/2), (y/2)-1)
57
    mon.write(errorText)
58
    -- msg
59
    mon.setTextColour(1)
60
    mon.setCursorPos((x/2) - (string.len(errors[index])/2), y/2)
61
    mon.write(errors[index])
62
    printError("ERROR: " .. errors[index])
63
64
    local timer = 10
65
    while timer > -1 do
66
        local countdownStr = "Next attempt in " .. timer
67
68
        mon.setTextColour(1)
69
        mon.setCursorPos((x/2) - (string.len(countdownStr)/2), (y/2)+2)
70
        draw((x/2) - (string.len(countdownStr)/2), string.len(countdownStr) + 1, (y/2)+2, 1, 32768)
71
        mon.setCursorPos((x/2) - (string.len(countdownStr)/2), (y/2)+2)
72
        mon.write(countdownStr)
73
        print(countdownStr)
74
75
        timer = timer -1
76
        os.sleep(1)
77
    end
78
79
    os.reboot()
80
end
81
82
--Round Function
83
function round(float)
84
    local int, part = math.modf(float)
85
    if float == math.abs(float) and part >= .5 then return int+1
86
    elseif part <= -.5 then return int-1
87
    end
88
    return int
89
end
90
91
--Round with 2 Decimals Function
92
function roundD(exact, quantum)
93
    local quant,frac = math.modf(exact/quantum)
94
    return quantum * (quant + (frac > 0.5 and 1 or 0))
95
end
96
97
-- format time
98
local timeUnits = {
99
    {threshold = 8553600, unit = "99+ days"},
100
    {threshold = 86400, unit = "days", divisor = 86400},
101
    {threshold = 3600, unit = "hours", divisor = 3600},
102
    {threshold = 60, unit = "min", divisor = 60},
103
    {threshold = 1, unit = "sec", divisor = 1}
104
}
105
106
function adjustTime(time)
107
    for _, unitData in ipairs(timeUnits) do
108
        if time >= unitData.threshold then
109
            local adjustedTime
110
            if unitData.divisor and unitData.divisor ~= 1 then
111
                adjustedTime = string.format("%.1f", time / unitData.divisor)
112
            elseif unitData.divisor then
113
                adjustedTime = math.floor(time / unitData.divisor)
114
            else
115
                adjustedTime = ""
116
            end
117
            return string.format("%s %s", adjustedTime, unitData.unit)
118
        end
119
    end
120
    return "0 sec."  -- fallback, if time is 0 or negative
121
end
122
123
--Conversion Function
124
function conversion(exact, text, addPlus, afterDecimalPoint)
125
    afterDecimalPoint = afterDecimalPoint or 0.1
126
    addPlus = addPlus or false
127
128
    local units = unitFormatCaps and {"", "K", "M", "G", "T", "P", "E", "Z", "Y"} or {"", "k", "m", "g", "t", "p", "e", "z", "y"}
129
    local pot = 1
130
    local absExact = math.abs(exact)
131
132
    while absExact >= (1000^pot) do
133
        pot = pot + 1
134
    end
135
136
    local value = roundD(exact / (1000^(pot - 1)), afterDecimalPoint)
137
    local out = tostring(value)
138
    
139
    if addPlus and value > 0 then out = "+" .. out end
140
    if text then out = out .. (unitFormatCaps and " " .. units[pot] or units[pot]) end
141
142
    return out
143
end
144
145
-- draw static elements (runs once)
146
function drawStatic()
147
    --Frame Induction Matrix
148
    draw(2, 2, 2, 1, 128)
149
    draw(22, 13, 2, 1, 128)
150
    draw(2, 1, 2, 17, 128)
151
    draw(2, 33, 18, 1, 128)
152
    draw(34, 1, 2, 17, 128)
153
    draw(2, 33, 8, 1, 128)
154
    mon.setCursorPos(5,2)
155
    mon.write("Induction Matrix")
156
 
157
    --Status
158
    draw(36, 2, 2, 1, 128)
159
    draw(36, 1, 2, 9, 128)
160
    draw(49, 1, 2, 9, 128)
161
    draw(36, 13, 10, 1, 128)
162
    draw(46, 4, 2, 1, 128)
163
    mon.setCursorPos(39,2)
164
    mon.write("Status")
165
    mon.setCursorPos(38,7)
166
    mon.write("Flow:")
167
 
168
    --Frame Stats
169
    draw(36, 1, 12, 7, 128)
170
    draw(49, 1, 12, 7, 128)
171
    draw(36, 13, 18, 1, 128)
172
    draw(36, 2, 12, 1, 128)
173
    draw(45, 4, 12, 1, 128)
174
    mon.setCursorPos(39,12)
175
    mon.write("Stats")
176
    
177
    --energyBar
178
    drawBar(4, 29, 4, 3, 256)
179
 
180
    --inputBar
181
    drawBar(4, 29, 11, 2, 256)
182
    mon.setCursorPos(4,10)
183
    mon.write("Input:")
184
    if displayMinMax then
185
        mon.setTextColour(128)
186
        mon.setCursorPos(4,13)
187-
        mon.write(" ")
187+
        mon.write("min")
188
        mon.setCursorPos(30,13)
189-
        mon.write("1.67G")
189+
        mon.write("max")
190
        mon.setTextColour(1)
191
    end
192
    
193
    --outputBar
194
    drawBar(4, 29, 15, 2, 256)
195
    mon.setCursorPos(4,14)
196
    mon.write("Output:")
197
    if displayMinMax then
198
        mon.setTextColour(128)
199
        mon.setCursorPos(4,17)
200-
        mon.write(" ")
200+
        mon.write("min")
201
        mon.setCursorPos(30,17)
202-
        mon.write("1.67G")
202+
        mon.write("max")
203
        mon.setTextColour(1)
204
    end
205
end
206
207
-- draw charts (runs every refresh)
208
function drawCharts()
209
    local percent = tostring(round((energy/dataCorrection)/(maxEnergy/dataCorrection)*100) .. "%")
210
    local percentPos = (29/2) - (string.len(percent)/2) + 4
211
    mon.setBackgroundColor(256)
212
    mon.setCursorPos(percentPos, 5)
213
    mon.write(percent)
214
    
215
    -- output meter
216
    drawBar(4, 29, 15, 2, 256)
217
    drawBar(4, round((lastOutput/transferCap)*29), 15, 2, 16384)
218
    if showTooltips and lastOutput == transferCap then
219
        mon.setBackgroundColor(16384)
220
        mon.setCursorPos(4, 16)
221
        mon.write("Maxed. Add/upgrade providers")
222
    end
223
224
    -- input meter
225
    drawBar(4, 29, 11, 2, 256)
226
    drawBar(4, round((lastInput/transferCap)*29), 11, 2, 32)
227
    if showTooltips and lastInput == transferCap then
228
        mon.setBackgroundColor(32)
229
        mon.setCursorPos(4, 12)
230
        mon.write("Maxed. Add/upgrade providers")
231
    end
232
233
    -- stored energy
234
    drawBar(4, 29, 4, 3, 256)
235
    drawBar(4, round(filledPercentage*29), 4, 3, 8)
236
237
    mon.setBackgroundColor(256)
238
    mon.setCursorPos(percentPos, 5)
239
    mon.write(percent)
240
    
241
    mon.setBackgroundColor(32768) -- reset to black
242
end
243
244
-- draw stats (runs every refresh)
245
function drawStats()
246
    local capacity = maxEnergy/dataCorrection
247
    local input = lastInput/dataCorrection
248
    local output = lastOutput/dataCorrection
249
    local stored = energy/dataCorrection
250
    local flow = input - output
251
    local maxTransfer = transferCap/dataCorrection
252
    
253
    
254
    -- STATS
255
    mon.setBackgroundColor(32768)
256
257
    mon.setCursorPos(38,14)
258
    mon.write("Cells: " .. installedCells)
259
260
    mon.setCursorPos(38,15)
261-
    mon.write("Prov: " .. installedProviders)
261+
    mon.write("I/O: " .. conversion(maxTransfer, true) .. "")
262
263
    mon.setCursorPos(38,16)
264
    mon.write("Cap: " .. conversion(capacity, false))
265
266
    -- stored energy
267
    draw(23, 11, 2, 1, 32768)
268
    mon.setCursorPos(24,2)
269
    mon.write(conversion(stored, true) .. "RF")
270
271
    -- input
272
    draw(10, 23, 10, 1, 32768)
273
    mon.setCursorPos(11,10)
274
    mon.write(conversion(input, true, true) .. "RF/t")
275
276
    -- output
277
    draw(11, 22, 14, 1, 32768)
278
    mon.setCursorPos(12,14)
279
    mon.write(conversion(output*-1, true) .. "RF/t")
280
281
    -- status
282
    local chargeStatus = "Charging"
283
    local timeStatus = "Full In:"
284
    local statusColour = 8192 -- green
285
    if (flow < 0) then
286
        statusColour = 16384 -- red
287
        chargeStatus = "Depleting"
288
        timeStatus = "Empty In:"
289
    elseif flow == 0 then
290
        statusColour = 16 -- red
291
        chargeStatus = "Idle"
292
    end
293
294
    -- Full/Empty In
295
    draw(38, 10, 5, 1, 32768)
296
    mon.setCursorPos(38,5)
297
    mon.write(timeStatus)
298
299
    mon.setTextColour(statusColour)
300
    draw(38, 10, 4, 1, 32768)
301
    mon.setCursorPos(38,4)
302
    mon.write(chargeStatus)
303
304
    -- time remaining
305
    local time = "Inf."
306
    if output < input then 
307
        time = adjustTime((capacity - stored) / (input - output) / 20)
308
    elseif output > input then
309
        time = adjustTime(stored / (output - input) / 20)
310
    end
311
    
312
    draw(38, 10, 6, 1, 32768)
313
    mon.setCursorPos(38,6)
314
    mon.write(time)
315
    
316
    -- flow
317
    draw(38, 10, 8, 1, 32768)
318
    mon.setCursorPos(38,8)
319
    mon.write(conversion(flow, true, true, 1) .. "RF/t")
320
    mon.setTextColour(1) -- reset
321
    
322
end
323
324
-- protective call
325
function protCall(func, errIndex)
326
    local success, result = pcall(func)
327
    if success and result then
328
        -- Function executed successfully, process the result
329
        return result
330
    else
331
        -- Function encountered an error
332
        displayError(errIndex)
333
    end
334
end
335
336
-- monitor check
337
if mon ~= nil then
338
    local x, y = mon.getSize()
339
    if x ~= 50 or y ~= 19 then
340
        print("ERROR: Incorrect monitor size. Monitor should be 5 wide and 3 tall.")
341
        return
342
    end
343
    
344
    mon.setBackgroundColor(32768)
345
    mon.clear()
346
    mon.setTextColour(1)
347
else
348
    print("No monitor found.")
349
    return
350
end
351
-- matrix check
352
while not mat or not mat.isFormed() do
353
    if not mat then
354
        displayError(2)
355
    elseif not mat.isFormed() then
356
        displayError(3)
357
    end
358
end
359
360
function lowBatAlarm()
361
    -- check the below line
362
    lowBatAlarmEnabled = (alarmPercent >= 0 and alarmPercent <= 100) and (round((energy/dataCorrection)/(maxEnergy/dataCorrection)*100) <= alarmPercent) -- and (lastInput/dataCorrection) - (lastOutput/dataCorrection) <= 0)
363
    if lowBatAlarmEnabled and not rs.getOutput("top") then
364
        setAlarm(true)
365
    elseif not lowBatAlarmEnabled and rs.getOutput("top") then
366
        setAlarm(false)
367
    end
368
end
369
370
function setAlarm(state)
371
    for _, side in pairs(rs.getSides()) do
372
        rs.setOutput(side, state)
373
    end
374
end
375
376
-- runs once
377
print("Induction Matrix monitor successfully loaded.")
378
print("Script by Ordiance & Broadbent")
379
energy, maxEnergy, installedCells, installedProviders, lastInput, lastOutput, filledPercentage, transferCap, lowBatAlarmEnabled = nil
380
mon.clear()
381
mon.setBackgroundColor(16384)
382
drawStatic()
383
384
-- runs every refresh
385
while true do
386
    energy = protCall(mat.getEnergy, 1)
387
    maxEnergy = protCall(mat.getMaxEnergy, 1)
388
    installedCells = protCall(mat.getInstalledCells, 1)
389
    installedProviders = protCall(mat.getInstalledProviders, 1)
390
    lastInput = protCall(mat.getLastInput, 1)
391
    lastOutput = protCall(mat.getLastOutput, 1)
392
    filledPercentage = protCall(mat.getEnergyFilledPercentage, 1)
393
    transferCap = protCall(mat.getTransferCap, 1)
394
395
    drawCharts()
396
    drawStats()
397
    lowBatAlarm()
398
    os.sleep(screenRefreshRate)
399
end
400