Add Create boiler status display
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
-- Create boiler status board for CC:Tweaked.
|
||||
-- Hardware:
|
||||
-- * one monitor
|
||||
-- * one Create Speedometer per boiler
|
||||
-- * one Create Stressometer on the main shaft
|
||||
-- * optionally one Advanced Peripherals Block Reader per boiler controller
|
||||
-- Everything must be connected to the computer, preferably using Wired Modems.
|
||||
|
||||
local EXPECTED_BOILERS = 3
|
||||
local REFRESH_SECONDS = 1
|
||||
local MONITOR_SCALE = 0.5
|
||||
local SPEEDOMETER_TYPE = "Create_Speedometer"
|
||||
local STRESSOMETER_TYPE = "Create_Stressometer"
|
||||
local BLOCK_READER_TYPE = "block_reader"
|
||||
|
||||
local monitor = peripheral.find("monitor")
|
||||
if not monitor then
|
||||
error("Kein Monitor gefunden. Monitor direkt anschliessen oder per Wired Modem verbinden.", 0)
|
||||
end
|
||||
|
||||
monitor.setTextScale(MONITOR_SCALE)
|
||||
monitor.setCursorBlink(false)
|
||||
|
||||
local function center(y, text, foreground, background)
|
||||
local width = monitor.getSize()
|
||||
text = tostring(text)
|
||||
if #text > width then text = text:sub(1, width) end
|
||||
local x = math.max(1, math.floor((width - #text) / 2) + 1)
|
||||
monitor.setBackgroundColor(background or colors.black)
|
||||
monitor.setTextColor(foreground or colors.white)
|
||||
monitor.setCursorPos(1, y)
|
||||
monitor.write((" "):rep(width))
|
||||
monitor.setCursorPos(x, y)
|
||||
monitor.write(text)
|
||||
end
|
||||
|
||||
local function getPeripheralsByType(wantedType)
|
||||
local names = {}
|
||||
for _, name in ipairs(peripheral.getNames()) do
|
||||
if peripheral.getType(name) == wantedType then
|
||||
names[#names + 1] = name
|
||||
end
|
||||
end
|
||||
table.sort(names)
|
||||
return names
|
||||
end
|
||||
|
||||
local function getValueIgnoringCase(data, wantedKeys)
|
||||
if type(data) ~= "table" then return nil end
|
||||
for key, value in pairs(data) do
|
||||
local lowered = tostring(key):lower()
|
||||
for _, wanted in ipairs(wantedKeys) do
|
||||
if lowered == wanted:lower() then return value end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function findBoilerData(data, visited)
|
||||
if type(data) ~= "table" then return nil end
|
||||
visited = visited or {}
|
||||
if visited[data] then return nil end
|
||||
visited[data] = true
|
||||
|
||||
local boiler = getValueIgnoringCase(data, { "Boiler" })
|
||||
if type(boiler) == "table" then return boiler end
|
||||
|
||||
local heat = getValueIgnoringCase(data, { "Heat", "activeHeat", "actualHeat" })
|
||||
local passive = getValueIgnoringCase(data, { "PassiveHeat", "passive" })
|
||||
if heat ~= nil or passive ~= nil then return data end
|
||||
|
||||
for _, value in pairs(data) do
|
||||
local found = findBoilerData(value, visited)
|
||||
if found then return found end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function readHeatMode(readerName)
|
||||
if not readerName then return "UNKNOWN" end
|
||||
local ok, data = pcall(peripheral.call, readerName, "getBlockData")
|
||||
if not ok then return "ERROR" end
|
||||
|
||||
local boiler = findBoilerData(data)
|
||||
if not boiler then return "UNKNOWN" end
|
||||
|
||||
local passive = getValueIgnoringCase(boiler, { "PassiveHeat", "passive" })
|
||||
local heat = tonumber(getValueIgnoringCase(boiler,
|
||||
{ "Heat", "activeHeat", "actualHeat", "boilerLevel", "level" }))
|
||||
|
||||
if passive == true or passive == 1 then return "CAMPFIRE" end
|
||||
if heat and heat >= 18 then return "SUPERHEATED" end
|
||||
if heat and heat > 0 then return "HEATED" end
|
||||
return "COLD"
|
||||
end
|
||||
|
||||
local function readBoiler(name, readerName)
|
||||
if not name then
|
||||
return "MISSING", 0, "UNKNOWN", colors.red
|
||||
end
|
||||
|
||||
local ok, speed = pcall(peripheral.call, name, "getSpeed")
|
||||
if not ok or type(speed) ~= "number" then
|
||||
return "ERROR", 0, "UNKNOWN", colors.red
|
||||
end
|
||||
|
||||
speed = math.abs(speed)
|
||||
if speed < 0.5 then
|
||||
return "STANDBY", 0, readHeatMode(readerName), colors.orange
|
||||
end
|
||||
return "ONLINE", speed, readHeatMode(readerName), colors.lime
|
||||
end
|
||||
|
||||
local function formatInteger(value)
|
||||
value = math.floor(math.abs(tonumber(value) or 0) + 0.5)
|
||||
local digits = tostring(value)
|
||||
local parts = {}
|
||||
while #digits > 3 do
|
||||
table.insert(parts, 1, digits:sub(-3))
|
||||
digits = digits:sub(1, -4)
|
||||
end
|
||||
table.insert(parts, 1, digits)
|
||||
return table.concat(parts, ".")
|
||||
end
|
||||
|
||||
local function readMainShaft(stressometerName)
|
||||
if not stressometerName then return nil, nil, nil end
|
||||
local okCapacity, capacity = pcall(peripheral.call,
|
||||
stressometerName, "getNetworkCapacity")
|
||||
local okUsage, usage = pcall(peripheral.call,
|
||||
stressometerName, "getNetworkStress")
|
||||
if not okCapacity or not okUsage then return nil, nil, nil end
|
||||
capacity = tonumber(capacity) or 0
|
||||
usage = tonumber(usage) or 0
|
||||
local load = capacity > 0 and usage / capacity * 100 or 0
|
||||
return capacity, usage, load
|
||||
end
|
||||
|
||||
local function render()
|
||||
local _, height = monitor.getSize()
|
||||
local speedometers = getPeripheralsByType(SPEEDOMETER_TYPE)
|
||||
local stressometers = getPeripheralsByType(STRESSOMETER_TYPE)
|
||||
local readers = getPeripheralsByType(BLOCK_READER_TYPE)
|
||||
|
||||
monitor.setBackgroundColor(colors.black)
|
||||
monitor.clear()
|
||||
center(1, "CREATE KRAFTWERK", colors.cyan)
|
||||
local firstRow = 3
|
||||
for index = 1, EXPECTED_BOILERS do
|
||||
local state, speed, heatMode, color = readBoiler(speedometers[index], readers[index])
|
||||
local row = firstRow + index - 1
|
||||
if row <= height then
|
||||
center(row, ("BOILER %d %-7s %5.1f RPM %s")
|
||||
:format(index, state, speed, heatMode), color)
|
||||
end
|
||||
end
|
||||
|
||||
local capacity, usage, load = readMainShaft(stressometers[1])
|
||||
if height >= 7 then center(7, "MAIN SHAFT", colors.cyan) end
|
||||
if capacity then
|
||||
if height >= 8 then center(8, "Capacity: " .. formatInteger(capacity) .. " SU", colors.white) end
|
||||
if height >= 9 then center(9, "Usage: " .. formatInteger(usage) .. " SU", colors.white) end
|
||||
if height >= 10 then
|
||||
local loadText = ("Load: %.1f %%"):format(load):gsub("%.", ",")
|
||||
center(10, loadText, load >= 90 and colors.red or load >= 70 and colors.orange or colors.lime)
|
||||
end
|
||||
else
|
||||
if height >= 8 then center(8, "Stressometer nicht gefunden", colors.red) end
|
||||
end
|
||||
|
||||
if height >= 12 then
|
||||
center(height, "Nur Anzeige - keine Steuerung", colors.gray)
|
||||
end
|
||||
|
||||
monitor.setTextColor(colors.white)
|
||||
monitor.setBackgroundColor(colors.black)
|
||||
term.setCursorPos(1, 1)
|
||||
end
|
||||
|
||||
while true do
|
||||
local ok, reason = pcall(render)
|
||||
if not ok then
|
||||
monitor.setBackgroundColor(colors.black)
|
||||
monitor.clear()
|
||||
center(1, "ANZEIGEFEHLER", colors.red)
|
||||
center(3, tostring(reason), colors.orange)
|
||||
end
|
||||
sleep(REFRESH_SECONDS)
|
||||
end
|
||||
Reference in New Issue
Block a user