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