Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- Draconic Energy Core Monitor 2.0 for ATM10
- Features: auto-find monitor/core, dynamic layout, tier auto-detect, flux stats & graph.
- Install: Place on a CC:Tweaked computer, run; monitor must be placed nearby.
- --]]
- -- Configuration
- UPDATE_DELAY = 0.25 -- seconds between updates
- GRAPH_POINTS = 600 -- history length for graph (max points)
- AVERAGE_SECONDS = 10 -- seconds for rolling average (unused in this version)
- AUTO_SCALE = true -- auto-scale graph Y-axis
- GRAPH_MODES = {"LINE","BAR","AREA","SMOOTH"} -- graph styles
- -- Color theme
- local THEME = {
- bg = colors.black,
- text = colors.white,
- barEmpty = colors.gray,
- barFill = colors.lime,
- graphFillPos = colors.green,
- graphFillNeg = colors.red
- }
- -- Safe write (handles colors)
- local function safeWrite(mon, x, y, txt, fg, bg)
- mon.setCursorPos(x, y)
- if fg then mon.setTextColor(fg) end
- if bg then mon.setBackgroundColor(bg) end
- mon.write(txt)
- end
- -- Find first monitor and core peripheral
- local function findMonitor()
- for _,name in ipairs(peripheral.getNames()) do
- if peripheral.getType(name) == "monitor" then
- return peripheral.wrap(name), name
- end
- end
- return nil, nil
- end
- local function findEnergyCore()
- for _,name in ipairs(peripheral.getNames()) do
- if peripheral.getType(name) == "draconic_rf_storage" then
- return peripheral.wrap(name), name
- end
- end
- return nil, nil
- end
- -- Map maxEnergy to tier (ATM10 standard values)
- local function getCoreTier(maxEnergy)
- if maxEnergy >= 9223372036854775807 then return 8
- elseif maxEnergy >= 2140000000000 then return 7
- elseif maxEnergy >= 356000000000 then return 6
- elseif maxEnergy >= 59300000000 then return 5
- elseif maxEnergy >= 9880000000 then return 4
- elseif maxEnergy >= 1640000000 then return 3
- elseif maxEnergy >= 273000000 then return 2
- else return 1 end
- end
- -- Format large number with suffix (k,M,G,T...)
- local function formatNumber(num)
- local abs = math.abs(num)
- if abs >= 1e12 then return string.format("%.2fT", num/1e12)
- elseif abs >= 1e9 then return string.format("%.2fG", num/1e9)
- elseif abs >= 1e6 then return string.format("%.2fM", num/1e6)
- elseif abs >= 1e3 then return string.format("%.1fk", num/1e3)
- else return tostring(num) end
- end
- -- Initialization: find peripherals, wrap them, clear screen
- local mon, monName, core, coreName
- local function initialize()
- mon, monName = findMonitor()
- if not mon then
- print("Error: Monitor not found!")
- return false
- end
- core, coreName = findEnergyCore()
- if not core then
- print("Error: Energy Core not found!")
- return false
- end
- if mon.setTextScale then mon.setTextScale(1) end
- mon.setBackgroundColor(THEME.bg)
- mon.clear()
- return true
- end
- -- Keep trying to initialize
- while not initialize() do
- os.sleep(1)
- end
- -- Data history and stats
- local fluxHistory = {}
- local peakIn, peakOut = 0, 0
- local startTime = os.epoch("utc")/1000
- local lastEnergy = core.getEnergyStored()
- local lastTime = os.epoch("utc")/1000
- local graphModeIndex = 1
- -- Main loop
- while true do
- -- Reinitialize if peripherals disconnected
- if not peripheral.isPresent(monName) or not peripheral.isPresent(coreName) then
- initialize()
- fluxHistory = {}
- peakIn, peakOut = 0, 0
- startTime = os.epoch("utc")/1000
- lastEnergy = core.getEnergyStored()
- lastTime = os.epoch("utc")/1000
- end
- -- Read core energy (safe call)
- local ok, energy = pcall(core.getEnergyStored, core)
- if not ok then
- initialize()
- goto continue
- end
- local maxEnergy = core.getMaxEnergyStored()
- local stored = energy
- local percent = stored / maxEnergy * 100
- local freeSpace = maxEnergy - stored
- -- Determine tier
- local tier = core.getTier and core.getTier() or getCoreTier(maxEnergy)
- -- Read transfer per tick (net)
- local transfer = core.getTransferPerTick()
- -- Attempt to use separate input/output if available
- local inputRate, outputRate = 0, 0
- if core.getInputPerTick and core.getOutputPerTick then
- inputRate = core.getInputPerTick()
- outputRate = core.getOutputPerTick()
- else
- -- Fallback: compute net flux per tick (assuming 20 ticks/sec)
- local now = os.epoch("utc")/1000
- local dt = now - lastTime
- local delta = stored - lastEnergy
- local rate = delta / (dt * 20)
- if rate >= 0 then inputRate = rate else outputRate = -rate end
- lastEnergy = stored
- lastTime = now
- end
- -- Update peaks
- if inputRate > peakIn then peakIn = inputRate end
- if outputRate > peakOut then peakOut = outputRate end
- -- Record net flux (positive=charging, negative=discharging)
- table.insert(fluxHistory, inputRate - outputRate)
- if #fluxHistory > GRAPH_POINTS then table.remove(fluxHistory, 1) end
- -- Begin rendering
- local w, h = mon.getSize()
- mon.setBackgroundColor(THEME.bg)
- mon.clear()
- -- Title (centered)
- safeWrite(mon, math.floor((w-20)/2), 1, "DRACONIC ENERGY CORE", THEME.text, THEME.bg)
- -- Storage bar (25% width)
- local barWidth = math.floor(w * 0.25)
- local filled = math.floor(barWidth * (stored / maxEnergy))
- for i=1,barWidth do
- if i <= filled then
- safeWrite(mon, i, 3, "█", THEME.text, THEME.barFill)
- else
- safeWrite(mon, i, 3, "█", THEME.text, THEME.barEmpty)
- end
- end
- safeWrite(mon, barWidth+2, 3,
- "Stored: "..formatNumber(stored).." / "..formatNumber(maxEnergy), THEME.text, THEME.bg)
- safeWrite(mon, barWidth+2, 4,
- string.format("Free: %s (%d%%)", formatNumber(freeSpace), math.floor(percent+0.5)), THEME.text, THEME.bg)
- -- Tier
- safeWrite(mon, 1, 5, "Tier: "..tier, THEME.text, THEME.bg)
- -- Current In/Out
- safeWrite(mon, 1, 6, "In: "..formatNumber(inputRate).." RF/t", THEME.text, THEME.bg)
- safeWrite(mon, math.floor(w/2)+1, 6, "Out: "..formatNumber(outputRate).." RF/t", THEME.text, THEME.bg)
- -- Peak In/Out
- safeWrite(mon, 1, 7, "Peak In: "..formatNumber(peakIn).." RF/t", THEME.text, THEME.bg)
- safeWrite(mon, math.floor(w/2)+1, 7, "Peak Out: "..formatNumber(peakOut).." RF/t", THEME.text, THEME.bg)
- -- ETA to full/empty
- if inputRate > 0 then
- local sec = (maxEnergy - stored) / (inputRate * 20)
- safeWrite(mon, 1, 8, "ETA Full: "..os.date("%H:%M:%S", sec), THEME.text, THEME.bg)
- else
- safeWrite(mon, 1, 8, "ETA Full: --:--:--", THEME.text, THEME.bg)
- end
- if outputRate > 0 then
- local sec = stored / (outputRate * 20)
- safeWrite(mon, math.floor(w/2)+1, 8, "ETA Empty: "..os.date("%H:%M:%S", sec), THEME.text, THEME.bg)
- else
- safeWrite(mon, math.floor(w/2)+1, 8, "ETA Empty: --:--:--", THEME.text, THEME.bg)
- end
- -- Uptime
- local elapsed = os.epoch("utc")/1000 - startTime
- safeWrite(mon, 1, 9,
- "Runtime: "..os.date("!%Hh%Mm%Ss", elapsed), THEME.text, THEME.bg)
- -- Separator line before graph
- for x=1,w do safeWrite(mon, x, 10, "-", THEME.text, THEME.bg) end
- -- Graph area (from line 11 to bottom)
- local graphOffset = 10
- local graphHeight = h - graphOffset
- local maxVal, minVal = 0, 0
- for _,v in ipairs(fluxHistory) do
- if v > maxVal then maxVal = v end
- if v < minVal then minVal = v end
- end
- if maxVal == minVal then
- maxVal = math.max(1, maxVal); minVal = -maxVal
- end
- local maxAbs = math.max(math.abs(maxVal), math.abs(minVal))
- local scale = (graphHeight/2) / maxAbs
- for i=1,w do
- local idx = #fluxHistory - w + i
- if idx >= 1 and fluxHistory[idx] then
- local val = fluxHistory[idx]
- local color = (val >= 0) and THEME.graphFillPos or THEME.graphFillNeg
- local barLen = math.floor(val * scale + 0.5)
- if GRAPH_MODES[graphModeIndex] == "BAR" then
- -- Draw vertical bar from center line
- if barLen >= 0 then
- for y=1,barLen do
- safeWrite(mon, i, graphOffset + math.floor(graphHeight/2) - y,
- "█", THEME.text, color)
- end
- else
- for y=1,-barLen do
- safeWrite(mon, i, graphOffset + math.floor(graphHeight/2) + y,
- "█", THEME.text, color)
- end
- end
- else
- -- LINE/AREA/SMOOTH: draw a point
- local midLine = graphOffset + math.floor(graphHeight/2)
- safeWrite(mon, i, midLine - barLen, "●", THEME.text, color)
- end
- end
- end
- -- Handle touch to toggle graph mode
- local timer = os.startTimer(UPDATE_DELAY)
- while true do
- local event, side, x, y = os.pullEvent()
- if event == "timer" then break end
- if event == "monitor_touch" and side == monName then
- graphModeIndex = (graphModeIndex % #GRAPH_MODES) + 1
- break
- end
- end
- ::continue::
- end
Advertisement
Add Comment
Please, Sign In to add comment