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 |