SHOW:
|
|
- or go back to the newest paste.
1 | --[[ | |
2 | Wolfe's Mekanism Induction Matrix Monitor | |
3 | Usage: Put computer with code near an Induction Port and a monitor (2x3 array should work fine) and run. | |
4 | Configuration: You can add a file called "config" with the options below, or append them to the command when running it via terminal: | |
5 | energy_type = 'FE' -- Energy type you want to use | |
6 | update_frequency = 1 -- Update frequency, in seconds | |
7 | text_scale = 1 -- The text scale on the monitor, use 0.5 if you want to run on less displays | |
8 | side_monitor = 'right' -- Hardcodes which side the monitor should be, defaults to auto-detection | |
9 | side_inductor = 'back' -- Hardcodes which side the Induction Port should be, defaults to auto-detection | |
10 | ]] | |
11 | ||
12 | -- | |
13 | -- Usage: Put computer near an Induction Port and a monitor , set the sides below and run. | |
14 | ||
15 | -- Default settings | |
16 | options = { | |
17 | energy_type = 'FE', | |
18 | update_frequency = 1, | |
19 | text_scale = 1, | |
20 | } | |
21 | ||
22 | -- Loads custom options from file (if available) | |
23 | if fs.exists('config') then | |
24 | -- Opens the file for reading | |
25 | local handle = fs.open('config') | |
26 | ||
27 | -- Reads configs | |
28 | raw_options = {} | |
29 | local line = handle.readLine() | |
30 | while line do | |
31 | table.insert(raw_options, line) | |
32 | line = handle.readLine() | |
33 | end | |
34 | ||
35 | -- Sets custom options | |
36 | custom_options = string.format('{%s}', table.concat(raw_options, '\n,')) | |
37 | ||
38 | -- Closes the handle properly | |
39 | handle.close() | |
40 | end | |
41 | ||
42 | -- Gets custom settings via arguments | |
43 | args = {...} | |
44 | if args and #args > 0 then | |
45 | -- Parses custom settings from args | |
46 | custom_options = string.format('{%s}', table.concat(args, '\n,')) | |
47 | end | |
48 | ||
49 | -- Detects custom options | |
50 | if custom_options then | |
51 | -- Debug only | |
52 | print('Running with custom options:') | |
53 | ||
54 | -- Makes sure we're dealing with a table to prevent code injection | |
55 | if '{' == custom_options:sub(1, 1) then | |
56 | -- Parses the object | |
57 | custom_options, err = loadstring(string.format('return %s', custom_options)) | |
58 | ||
59 | -- Handles invalid object | |
60 | if not custom_options then | |
61 | print('Invalid options:') | |
62 | print(err) | |
63 | else | |
64 | -- Replaces settings | |
65 | for k, v in pairs(custom_options()) do | |
66 | print(string.format('%s = %s', k, v)) | |
67 | options[k] = v | |
68 | end | |
69 | end | |
70 | end | |
71 | end | |
72 | ||
73 | -- Auto-detects sides | |
74 | for _, side in pairs(peripheral.getNames()) do | |
75 | -- Auto-detects monitor | |
76 | if 'monitor' == peripheral.getType(side) and (not options.side_monitor) then | |
77 | options.side_monitor = side | |
78 | end | |
79 | ||
80 | -- Auto-detects Induction Port | |
81 | if 'inductionPort' == peripheral.getType(side) and (not options.side_inductor) then | |
82 | options.side_inductor = side | |
83 | end | |
84 | end | |
85 | ||
86 | -- Connects to Peripherals | |
87 | monitor = peripheral.wrap(options.side_monitor) | |
88 | ||
89 | -- Queues a new print command to be sent | |
90 | buffer = {} | |
91 | function queue (text) | |
92 | table.insert(buffer, text) | |
93 | end | |
94 | ||
95 | -- Queues a new print command with string.format | |
96 | function queuef (fmt, ...) | |
97 | queue(string.format(fmt, ...)) | |
98 | end | |
99 | ||
100 | -- Flushes (prints) buffer content | |
101 | function queue_flush () | |
102 | -- Clears terminal | |
103 | term.clear() | |
104 | term.setCursorPos(1, 1) | |
105 | ||
106 | -- Writes new data | |
107 | print(table.concat(buffer, '\n')) | |
108 | buffer = {} | |
109 | end | |
110 | ||
111 | -- Formats time | |
112 | function time (secs) | |
113 | -- Prepare value | |
114 | secs = math.floor(secs) | |
115 | ||
116 | -- Days | |
117 | local weeks = math.floor(secs / 604800) | |
118 | secs = secs - (604800 * weeks) | |
119 | ||
120 | -- Days | |
121 | local days = math.floor(secs / 86400) | |
122 | secs = secs - (86400 * days) | |
123 | ||
124 | -- Hours | |
125 | local hours = math.floor(secs / 3600) | |
126 | secs = secs - (3600 * hours) | |
127 | ||
128 | -- Minutes | |
129 | local mins = math.floor(secs / 60) | |
130 | secs = secs - (60 * mins) | |
131 | ||
132 | -- If we have more than 72h worth of storage, switch to week, day, hour format | |
133 | if weeks > 0 then | |
134 | return string.format('%dwk %dd %dh', weeks, days, hours) | |
135 | elseif days >= 3 then | |
136 | return string.format('%dd %dh', days, hours) | |
137 | end | |
138 | ||
139 | -- Formatting to have trailing zeros on H:MM:SS | |
140 | return string.format('%d:%02d:%02d', hours, mins, secs) | |
141 | end | |
142 | ||
143 | -- Rounds number | |
144 | function rnd (val, dec) | |
145 | local X = math.pow(10, dec) | |
146 | return math.floor(val * X) / X | |
147 | end | |
148 | ||
149 | -- Converts to percentage | |
150 | function pct (val, dec) | |
151 | return rnd(100 * val, dec or 1) .. '%' | |
152 | end | |
153 | ||
154 | -- Converts to readable power | |
155 | function pwr (val, dec) | |
156 | local pre = '' | |
157 | local suf = '' | |
158 | ||
159 | local is_neg = false | |
160 | if val < 0 then | |
161 | pre = '-' | |
162 | is_neg = true | |
163 | val = -val | |
164 | end | |
165 | ||
166 | val = energy_function(val) | |
167 | ||
168 | if val > 1000 then | |
169 | suf = 'k' | |
170 | val = val / 1000 | |
171 | end | |
172 | ||
173 | if val > 1000 then | |
174 | suf = 'M' | |
175 | val = val / 1000 | |
176 | end | |
177 | ||
178 | if val > 1000 then | |
179 | suf = 'G' | |
180 | val = val / 1000 | |
181 | end | |
182 | ||
183 | if val > 1000 then | |
184 | suf = 'T' | |
185 | val = val / 1000 | |
186 | end | |
187 | ||
188 | return string.format('%s%s%s%s', pre, rnd(val, dec or 1), suf, energy_type) | |
189 | end | |
190 | ||
191 | -- Checks induction port | |
192 | function check_connection () | |
193 | return inductor and inductor.getEnergy and inductor.getLastInput | |
194 | end | |
195 | ||
196 | -- Detects energy type, sets energy function | |
197 | energy_type = options.energy_type | |
198 | energy_function = mekanismEnergyHelper[string.format('joulesTo%s', energy_type)] | |
199 | ||
200 | -- Function not found, use default Joules and a stub | |
201 | if not energy_function then | |
202 | energy_type = 'J' | |
203 | energy_function = function (val) return val end | |
204 | end | |
205 | ||
206 | -- Starts monitor | |
207 | term.redirect(monitor) | |
208 | monitor.setTextScale(options.text_scale) | |
209 | ||
210 | -- Checks if Inductor Port is missing or multiblock not ready | |
211 | inductor = peripheral.wrap(options.side_inductor) | |
212 | while not check_connection() do | |
213 | -- Writes error message | |
214 | queue('Ind.Port not found') | |
215 | queue('Check connections.') | |
216 | queue('Waiting...') | |
217 | ||
218 | -- Prints | |
219 | queue_flush() | |
220 | ||
221 | -- Wait for next update | |
222 | os.sleep(options.update_frequency) | |
223 | ||
224 | -- Tries to detect port | |
225 | if not options.side_inductor then | |
226 | for _, side in pairs(peripheral.getNames()) do | |
227 | -- Tries to find an induction port | |
228 | if 'inductionPort' == peripheral.getType(side) then | |
229 | options.side_inductor = side | |
230 | inductor = peripheral.wrap(options.side_inductor) | |
231 | end | |
232 | end | |
233 | else | |
234 | -- Try again on pre-set port | |
235 | inductor = peripheral.wrap(options.side_inductor) | |
236 | end | |
237 | end | |
238 | ||
239 | -- Initializes balance | |
240 | balance = inductor.getEnergy() | |
241 | while true do | |
242 | local status, err = pcall(function () | |
243 | -- Main script | |
244 | queue('Ind.Matrix Monitor') | |
245 | queue('------------------') | |
246 | queue('') | |
247 | queuef('Power : %s', pwr(inductor.getEnergy())) | |
248 | queuef('Limit : %s', pwr(inductor.getMaxEnergy())) | |
249 | queuef('Charge: %s', pct(inductor.getEnergyFilledPercentage())) | |
250 | queue('') | |
251 | queuef('Input : %s', pwr(inductor.getLastInput())) | |
252 | queuef('Output: %s', pwr(inductor.getLastOutput())) | |
253 | queuef('Max IO: %s/t', pwr(inductor.getTransferCap())) | |
254 | queue('') | |
255 | ||
256 | -- Power balance per second | |
257 | local balance_last = balance | |
258 | balance = inductor.getEnergy() | |
259 | local balance_change = (balance - balance_last) / options.update_frequency | |
260 | ||
261 | -- If we have negative value here, we'll save a character by removing the space so it fits same line | |
262 | if balance_change < 0 then | |
263 | queuef('Change:%s/s', pwr(balance_change)) | |
264 | else | |
265 | queuef('Change: %s/s', pwr(balance_change)) | |
266 | end | |
267 | ||
268 | -- Status (charged/depleted in) | |
269 | queue('Status:') | |
270 | if balance_change > 0 then | |
271 | -- Charging | |
272 | local remaining_charge = inductor.getMaxEnergy() - inductor.getEnergy() | |
273 | local seconds_remaining = remaining_charge / balance_change | |
274 | queuef('Charg. %s', time(seconds_remaining)) | |
275 | elseif balance_change < 0 then | |
276 | -- Discharging | |
277 | local remaining_charge = inductor.getEnergy() | |
278 | local seconds_remaining = remaining_charge / -balance_change | |
279 | queuef('Disch. %s', time(seconds_remaining)) | |
280 | else | |
281 | -- No changes, so we won't be charged or depleted, rare. | |
282 | queue('Idle') | |
283 | end | |
284 | end) | |
285 | ||
286 | -- Checks for errors (might be disconnected) | |
287 | if not status then | |
288 | -- Clears buffer first | |
289 | buffer = {} | |
290 | ||
291 | -- Shows error message | |
292 | queue('Error reading data') | |
293 | queue('Check connections.') | |
294 | queue('------------------') | |
295 | queue(err) | |
296 | end | |
297 | ||
298 | -- Prints | |
299 | queue_flush() | |
300 | ||
301 | -- Wait for next update | |
302 | os.sleep(options.update_frequency) | |
303 | end |