Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Usage: em <monitorSide> <redstoneSide> [activate%] [deactivate%]
- -- Example: em right back 30 80
- local tArgs = {...}
- if #tArgs < 2 then
- print("Usage: em <monitorSide> <redstoneSide> [activate%] [deactivate%]")
- return
- end
- local monitorSide = tArgs[1]
- local redstoneSide = tArgs[2]
- local activateThreshold = tonumber(tArgs[3]) or 25
- local deactivateThreshold = tonumber(tArgs[4]) or 75
- local monitor = peripheral.wrap(monitorSide)
- if not monitor then
- print("Error: No monitor on side '" .. monitorSide .. "'")
- return
- end
- monitor.setTextScale(0.8)
- local w, h = monitor.getSize()
- -- Smart line redraw (no flicker)
- local lastDrawn = {}
- local function smartWriteLine(y, text, colour, bg)
- if lastDrawn[y] ~= text then
- monitor.setCursorPos(1, y)
- monitor.setTextColour(colour or colours.white)
- monitor.setBackgroundColour(bg or colours.black)
- monitor.clearLine()
- monitor.write(text)
- monitor.setTextColour(colours.white)
- monitor.setBackgroundColour(colours.black)
- lastDrawn[y] = text
- end
- end
- local function divider(y)
- smartWriteLine(y, string.rep("-", w))
- end
- -- Fill bar with colour ramp
- local function drawFillBar(y, percent)
- local barWidth = w - 2
- local filledBars = math.floor((percent / 100) * barWidth)
- monitor.setCursorPos(1, y)
- monitor.write("[")
- for i = 1, barWidth do
- if i <= filledBars then
- local p = (i / barWidth) * 100
- local colour = colours.red
- if p > 80 then colour = colours.green
- elseif p > 50 then colour = colours.yellow
- elseif p > 20 then colour = colours.orange end
- monitor.setBackgroundColour(colour)
- monitor.write(" ")
- monitor.setBackgroundColour(colours.black)
- else
- monitor.write(" ")
- end
- end
- monitor.write("]")
- end
- -- Discover IC2 storage blocks
- local function findStorages()
- local list = {}
- for _, name in ipairs(peripheral.getNames()) do
- if string.find(name, "ic2:batbox") or
- string.find(name, "ic2:cesu") or
- string.find(name, "ic2:mfe") or
- string.find(name, "ic2:mfsu") then
- table.insert(list, {peripheral.wrap(name), name})
- end
- end
- return list
- end
- local function formatEU(energy)
- if energy >= 1000000 then
- return string.format("%.1f M EU", energy / 1000000)
- elseif energy >= 1000 then
- return string.format("%.1f k EU", energy / 1000)
- else
- return string.format("%.0f EU", energy)
- end
- end
- local function formatTime(seconds)
- seconds = math.max(0, math.floor(seconds))
- local hh = math.floor(seconds / 3600)
- local mm = math.floor((seconds % 3600) / 60)
- local ss = seconds % 60
- return string.format("%02d:%02d:%02d", hh, mm, ss)
- end
- -- State
- local lastTotals = {} -- stores last total and per-block stored values
- local redstoneActive = false
- local currentPage = 1
- local totalPages = 1
- local lastPage = nil
- -- Combined totals across all storages
- local function getTotals(storages)
- local cap, stored = 0, 0
- for _, s in ipairs(storages) do
- cap = cap + (s[1].getEUCapacity() or 0)
- stored = stored + (s[1].getEUStored() or 0)
- end
- return cap, stored
- end
- -- Page 1: Combined overview
- local function drawCombined(storages)
- local cap, stored = getTotals(storages)
- local fill = (cap > 0) and (stored / cap * 100) or 0
- local change = stored - (lastTotals.total or stored)
- lastTotals.total = stored
- local status = "Stable"
- if change > 0 then status = "Charging"
- elseif change < 0 then status = "Discharging" end
- -- Time estimate (in seconds, assuming 1s cadence)
- local timeString = "Stable"
- if change > 0 then
- local secondsToFull = (cap - stored) / change
- timeString = "Full in " .. formatTime(secondsToFull)
- elseif change < 0 then
- local secondsToEmpty = stored / math.abs(change)
- timeString = "Empty in " .. formatTime(secondsToEmpty)
- end
- -- Redstone hysteresis by fill %
- if fill < activateThreshold then
- redstone.setOutput(redstoneSide, true)
- redstoneActive = true
- elseif fill > deactivateThreshold then
- redstone.setOutput(redstoneSide, false)
- redstoneActive = false
- end
- smartWriteLine(1, "IC2 Network Storage (Combined)")
- smartWriteLine(2, "Capacity : " .. formatEU(cap))
- smartWriteLine(3, "Stored : " .. formatEU(stored))
- smartWriteLine(4, string.format("Filled : %.2f%%", fill), fill < activateThreshold and colours.red or colours.white)
- -- Fill bar line cleared explicitly to avoid artifacts
- monitor.setCursorPos(1, 5); monitor.clearLine()
- drawFillBar(5, fill)
- divider(6)
- smartWriteLine(7, "Status : " .. status .. " (" .. change .. " EU/t)")
- divider(8)
- smartWriteLine(9, timeString)
- if change >= 0 then
- smartWriteLine(10, "Actual In : " .. change .. " EU/t")
- smartWriteLine(11, "Actual Out: 0 EU/t")
- else
- smartWriteLine(10, "Actual In : 0 EU/t")
- smartWriteLine(11, "Actual Out: " .. math.abs(change) .. " EU/t")
- end
- smartWriteLine(12, redstoneActive and "Redstone: ACTIVE" or "Redstone: Inactive",
- redstoneActive and colours.red or colours.white)
- end
- -- Page 2+: Per-block breakdown with overflow paging
- local function drawBreakdown(storages, page)
- local line = 1
- local contentBottom = h - 4 -- reserve rows h-3 (label), h-2 (blank), h-1 & h (buttons)
- local perPage = contentBottom -- usable rows for content
- local startIndex = (page - 2) * perPage + 1
- local endIndex = math.min(startIndex + perPage - 1, #storages)
- for i = startIndex, endIndex do
- local block, name = storages[i][1], storages[i][2]
- local cap = block.getEUCapacity() or 0
- local stored = block.getEUStored() or 0
- local fill = (cap > 0) and (stored / cap * 100) or 0
- local change = stored - (lastTotals[name] or stored)
- lastTotals[name] = stored
- local status = "Stable"
- if change > 0 then status = "Charging"
- elseif change < 0 then status = "Discharging" end
- local timeString = "Stable"
- if change > 0 then
- local secondsToFull = (cap - stored) / change
- timeString = "Full in " .. formatTime(secondsToFull)
- elseif change < 0 then
- local secondsToEmpty = stored / math.abs(change)
- timeString = "Empty in " .. formatTime(secondsToEmpty)
- end
- smartWriteLine(line, name .. " (" .. string.format("%.1f%%", fill) .. ")",
- fill < activateThreshold and colours.red or colours.white)
- line = line + 1
- monitor.setCursorPos(1, line); monitor.clearLine()
- drawFillBar(line, fill)
- line = line + 1
- smartWriteLine(line, "Status: " .. status .. " (" .. change .. " EU/t)")
- line = line + 1
- smartWriteLine(line, timeString)
- line = line + 1
- if change >= 0 then
- smartWriteLine(line, "In : " .. change .. " EU/t")
- line = line + 1
- smartWriteLine(line, "Out: 0 EU/t")
- else
- smartWriteLine(line, "In : 0 EU/t")
- line = line + 1
- smartWriteLine(line, "Out: " .. math.abs(change) .. " EU/t")
- end
- line = line + 1
- divider(line)
- line = line + 1
- if line > contentBottom then break end
- end
- end
- -- Two-row navigation bar with centered labels
- local function drawNav(currentPageView, totalPagesView)
- -- Page indicator at h-3
- local label = " Page " .. currentPageView .. " / " .. totalPagesView .. " "
- local spacing = math.floor((w - #label) / 2)
- smartWriteLine(h-3, string.rep(" ", spacing) .. label)
- local half = math.floor(w / 2)
- -- Draw button backgrounds (rows h-1 and h)
- monitor.setBackgroundColour(colours.red)
- monitor.setTextColour(colours.white)
- for y = h-1, h do
- monitor.setCursorPos(1, y)
- monitor.write(string.rep(" ", half))
- end
- monitor.setBackgroundColour(colours.green)
- for y = h-1, h do
- monitor.setCursorPos(half + 1, y)
- monitor.write(string.rep(" ", w - half))
- end
- -- Labels on bottom row (center vertically)
- monitor.setBackgroundColour(colours.red)
- monitor.setCursorPos(2, h)
- monitor.write(" Prev ")
- monitor.setBackgroundColour(colours.green)
- monitor.setCursorPos(half + 2, h)
- monitor.write(" Next ")
- monitor.setBackgroundColour(colours.black)
- monitor.setTextColour(colours.white)
- end
- -- Calculate total pages (1 overview + N breakdown pages)
- local function updateTotalPages(storages)
- local contentBottom = h - 4
- local perPage = math.max(1, contentBottom)
- local breakdownPages = math.ceil(#storages / perPage)
- totalPages = 1 + breakdownPages
- end
- -- Touch handler: detect presses on either row of the buttons
- local function handleTouch(x, y)
- local half = math.floor(w / 2)
- if y == h or y == h - 1 then
- if x <= half then
- currentPage = math.max(1, currentPage - 1)
- else
- currentPage = math.min(totalPages, currentPage + 1)
- end
- return true
- end
- return false
- end
- -- Main loop: refresh, draw current page, draw nav, wait for touch or timer
- while true do
- local storages = findStorages()
- updateTotalPages(storages)
- -- One-time clear on page switch to avoid ghost text
- if currentPage ~= lastPage then
- monitor.clear()
- lastDrawn = {} -- reset cache so smartWriteLine redraws everything
- lastPage = currentPage
- else
- -- Clear content cache each tick so changing lines update properly
- for y = 1, h-4 do
- lastDrawn[y] = nil
- end
- end
- if currentPage == 1 then
- drawCombined(storages)
- else
- drawBreakdown(storages, currentPage)
- end
- drawNav(currentPage, totalPages)
- -- Timer for 1-second cadence while accepting touch
- local timer = os.startTimer(1)
- while true do
- local e, p1, p2, p3 = os.pullEvent()
- if e == "monitor_touch" then
- local side, x, y = p1, p2, p3
- if handleTouch(x, y) then
- break
- end
- elseif e == "timer" and p1 == timer then
- break
- end
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment