EnergyMonitor/lib/inputClient.lua
2023-11-03 20:46:25 +01:00

296 lines
8.2 KiB
Lua

-- set system seed
math.randomseed(os.time())
-- system options/components
local system = {}
function set_converter(options)
return mekanismEnergyHelper[
string.format('joulesTo%s', options.unit)
]
end
-- convert number to compact form (1000 => 1k)
function compact_number(number)
local units = {'k', 'M', 'G', 'T'}
local index = 0
-- scale number, increment unit index
while number >= 1000 do
number = number / 1000
index = index + 1
end
-- keep 2 decimals, add units
return string.format('%.2f %s', number, units[index] or ' ')
end
-- format number with energy (/transfer) units
function format_energy(options, number, transfer)
local energy = number
-- compact number
if options.compact then
energy = compact_number(number)
else
energy = energy .. ' '
end
-- append transfer unit
local t_unit = ' '
if transfer or false then
t_unit = '/t'
end
-- build string
return energy .. options.unit .. t_unit
end
-- format percentages as number with two decimals and padded unit
function format_percent(options, number, mult)
-- multiply by default
local percent = number
if mult == nil or mult == true then
percent = number * 100
end
return string.format('%.2f ', percent) .. '% ' .. string.rep(' ', #(options.unit or ''))
end
-- format temperature as number with two decimals and padded unit
function format_temp(options, number)
local temperature = number
-- compact number
if options.compact then temperature = compact_number(number)
else temperature = string.format('%.2f ', temperature) end
-- build string
return temperature .. 'K ' .. string.rep(' ', #(options.unit or ''))
end
-- format liquids as compact number and padded unit
function format_liquid(options, number, transfer)
local liquid = number
-- compact number
if options.compact then
liquid = compact_number(number)
else
liquid = liquid .. ' '
end
-- append transfer unit
local t_unit = ' '
if transfer or false then
t_unit = '/t'
end
return liquid .. 'mB' .. t_unit
end
function find_peripheral_component(name)
for _, side in pairs(peripheral.getNames()) do
if peripheral.getType(side) == name then
return peripheral.wrap(side)
end
end
return nil
end
-- scan for system components
function scan_components(name)
-- try finding with peripherals
local component = find_peripheral_component(name)
local modem = find_peripheral_component('modem')
-- check if components were found
local found_component = not component
local found_modem = not modem
-- output corresponding error messages
if found_component or found_modem then
print('Invalid configuration detected!')
if found_component then print('Main component not found!') end
if found_modem then print('Modem not found!') end
end
-- return component data
local success = not (found_component or found_modem)
return {
success = success,
main = component,
modem = modem,
}
end
-- split string by delimiter
function split_string(text, delimiter)
local result = {}
for match in (text .. delimiter):gmatch('(.-)' .. delimiter) do
table.insert(result, match)
end
return result
end
-- initialize ender modem
function init_modem(options)
system.channel = nil
-- open initializer port
system.modem.open(1)
-- try initializing communication
local count = 1
while true do
local channel = math.random(2, 1 + options.channels)
-- open reply channel
system.modem.open(channel)
system.modem.transmit(1, channel, options.name)
term.setCursorPos(1, 6)
print('\nTry #' .. count)
print('Trying channel ' .. channel .. string.rep(' ', #tostring(1 + options.channels)))
-- increment try-counter
count = count + 1
-- wait for response
local timer_id = os.startTimer(options.timeout)
while true do
local event, _, senderChannel, _, message, _ = os.pullEvent()
if event == 'modem_message' and senderChannel == channel then
local result = split_string(message, ' ')
-- save channel for communication
if result[1] == 'ready' then
system.width = tonumber(result[2])
system.channel = channel
-- cancel timer on success
os.cancelTimer(timer_id)
-- already in use; reset channel
elseif message == 'used' then
system.modem.close(channel)
end
break
-- retry on timeout
elseif event == 'timer' then break end
end
-- success condition
if system.channel then break end
end
-- close initializer port
system.modem.close(1)
end
-- scan for components and retry on fail
function wait_for_components(options)
system.timeout = false
local count = 1
-- fixed print out
term.clear()
term.setCursorPos(1, 1)
print('Scanning for valid configuration:')
while true do
-- reset terminal
term.setCursorPos(1, 2)
-- output retry count
print('Try #' .. count .. '\n')
count = count + 1
-- scan for components
local components = scan_components(options.port)
if components.success then
-- output success message
print('Success!')
print('Trying to connect to receiver . . .')
-- set system components
system.main = components.main
system.modem = components.modem
init_modem(options)
print('\nSuccess!')
return true
end
-- components not found, wait to retry
print('Failed!')
os.sleep(options.timeout)
end
end
-- queue message for transfer
function message(buffer, text)
table.insert(buffer, text)
end
-- output aligned string by padding whitespaces in the middle of it to reach width
function message_aligned(buffer, text, value, width)
local str = tostring(value)
local length = width - #str
message(buffer, string.format("%-" .. length .. "s%s", text, value))
end
-- transmit buffered messages over ender modem
function transmit_messages(options, buffer)
system.modem.transmit(system.channel, system.channel, table.concat(buffer, '\n'))
local timer_id = os.startTimer(options.timeout)
while true do
local event, _, senderChannel, _, message, _ = os.pullEvent()
-- respond to corresponding message only
if event == 'modem_message' and senderChannel == system.channel and message == 'ok' then
-- cancel timer on success
os.cancelTimer(timer_id)
return
-- cancel on timeout
elseif event == 'timer' then
system.timeout = true
return
end
end
end
function respond_print(options, name)
-- buffer for messages
local buffer = {}
-- generate messages in buffer
execute_funcs(system.width, system.main, buffer, name)
-- transmit messages in form of buffer
if #buffer > 0 then transmit_messages(options, buffer) end
end
function event_listener(options)
while true do
local _, _, senderChannel, _, message, _ = os.pullEvent('modem_message')
-- respond to corresponding message only
if senderChannel == system.channel then
-- send main display message
respond_print(options, message)
end
end
end
function execute_funcs(width, component, buffer, name)
for key, func in pairs(system.funcs) do
if type(func) == "function" and key == name then
func(width, component, buffer)
end
end
end
function run_client(options, funcs)
-- save response functions
system.funcs = funcs
-- get components and run permanently
while wait_for_components(options) do
-- reset terminal
term.clear()
-- run while all components are detected
while scan_components(options.port).success and (not system.timeout) do
event_listener(options)
end
end
end