Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- graph_ui.lua (run on your graph‐UI computer)
- -- Peripheral wrapping & term redirect
- rednet.open("left")
- local mon = assert(peripheral.wrap("monitor_4"), "Monitor not found")
- term.redirect(mon)
- -- Configuration
- local HISTORY_MAX = 100 -- number of data points to keep
- local INTERVAL = 1 -- seconds between samples
- -- histories
- local feHistory = {}
- local pctHistory = {}
- -- Subpixel hi-res line helpers (2x2 per char cell)
- local subpixelGrid = {}
- local function setSubpixel(gx, gy, col)
- local cx = math.floor((gx-1)/2)+1
- local cy = math.floor((gy-1)/2)+1
- local sx = (gx-1)%2
- local sy = (gy-1)%2
- local bit = sy*2 + sx -- 0..3
- subpixelGrid[cy] = subpixelGrid[cy] or {}
- local cell = subpixelGrid[cy][cx] or {mask=0, col=col}
- cell.mask = bit32.bor(cell.mask, bit32.lshift(1, bit))
- cell.col = col or cell.col
- subpixelGrid[cy][cx] = cell
- end
- local function drawLine(x1, y1, x2, y2, col)
- -- All coords are in normal monitor space; we'll scale up by 2 for subpixels
- x1 = math.floor(x1 * 2 + 0.5)
- y1 = math.floor(y1 * 2 + 0.5)
- x2 = math.floor(x2 * 2 + 0.5)
- y2 = math.floor(y2 * 2 + 0.5)
- local dx = math.abs(x2 - x1)
- local dy = math.abs(y2 - y1)
- local sx = x1 < x2 and 1 or -1
- local sy = y1 < y2 and 1 or -1
- local err = dx - dy
- while true do
- setSubpixel(x1, y1, col)
- if x1 == x2 and y1 == y2 then break end
- local e2 = 2 * err
- if e2 > -dy then err = err - dy; x1 = x1 + sx end
- if e2 < dx then err = err + dx; y1 = y1 + sy end
- end
- end
- local function renderSubpixels(mon)
- for y, row in pairs(subpixelGrid) do
- for x, cell in pairs(row) do
- mon.setCursorPos(x, y)
- mon.setTextColor(cell.col or colors.white)
- mon.write(string.char(128 + (cell.mask or 0)))
- end
- end
- mon.setTextColor(colors.white)
- end
- local function clearSubpixels()
- subpixelGrid = {}
- end
- local function addTimestamp()
- if not feHistory.timestamps then feHistory.timestamps = {} end
- local t = textutils.formatTime(os.time(), true)
- table.insert(feHistory.timestamps, t)
- if #feHistory.timestamps > HISTORY_MAX then
- table.remove(feHistory.timestamps, 1)
- end
- end
- -- Draw graph background (zero line as "_"), return layout + FE range
- local function drawBackground()
- mon.setBackgroundColor(colors.black)
- mon.clear()
- clearSubpixels()
- local w, h = mon.getSize()
- local left, top = 3, 3
- local right, bottom = w - 2, h - 2
- local graph_w = right - left
- local graph_h = bottom - top
- if #feHistory == 0 then
- return left, top, right, bottom, graph_w, graph_h, 0, 1, 1
- end
- -- compute FE history min/max including zero
- local minV, maxV = feHistory[1], feHistory[1]
- for i = 2, #feHistory do
- local v = feHistory[i]
- if v < minV then minV = v end
- if v > maxV then maxV = v end
- end
- minV = math.min(minV, 0)
- maxV = math.max(maxV, 0)
- local range = maxV - minV
- -- draw horizontal zero line as subpixels (use gray)
- local zero_t = (0 - minV) / range
- local zero_y = bottom - math.floor(zero_t * graph_h + 0.5)
- drawLine(left, zero_y, right, zero_y, colors.gray)
- -- draw fixed vertical grey bars and "seconds ago" labels at the bottom
- local divisions = 10 -- number of spaces, so 10 bars (adjust as you want)
- local labelRow = bottom + 1
- local stepDiv = graph_w / divisions
- for d = 0, divisions do
- local x = left + math.floor(d * stepDiv + 0.5)
- drawLine(x, top, x, bottom, colors.gray)
- -- offset label in seconds ago
- local secondsAgo = (divisions - d) * INTERVAL * math.floor(HISTORY_MAX / divisions)
- mon.setCursorPos(x-2, labelRow)
- mon.setTextColor(colors.lightGray)
- mon.write("-" .. tostring(secondsAgo))
- mon.setTextColor(colors.white)
- end
- return left, top, right, bottom, graph_w, graph_h, minV, maxV, range
- end
- -- Plot battery % graph in red (no labels here)
- local function drawPctGraph(left, top, right, bottom, gw, gh)
- if #pctHistory == 0 then return end
- local step = gw / (HISTORY_MAX - 1)
- local offset = HISTORY_MAX - #pctHistory
- local px, py
- for i, p in ipairs(pctHistory) do
- local x = left + math.floor((offset + i - 1) * step + 0.5)
- local y = bottom - math.floor((p / 100) * gh + 0.5)
- if px then drawLine(px, py, x, y, colors.red) end
- px, py = x, y
- end
- end
- -- Plot FE/t graph in green (no labels here)
- local function drawFEGraph(left, top, right, bottom, gw, gh, vmin, vmax, vrange)
- if #feHistory == 0 then return end
- local step = gw / (HISTORY_MAX - 1)
- local offset = HISTORY_MAX - #feHistory
- local px, py
- for i, v in ipairs(feHistory) do
- local x = left + math.floor((offset + i - 1) * step + 0.5)
- local t = (v - vmin) / vrange
- local y = bottom - math.floor(t * gh + 0.5)
- if px then drawLine(px, py, x, y, colors.lime) end
- px, py = x, y
- end
- end
- -- Draw battery % min/max/current labels (drawn LAST)
- local function drawPctLabels(left, bottom, gw, gh, offset)
- if #pctHistory == 0 then return end
- local minIdx, maxIdx = 1, 1
- for i = 2, #pctHistory do
- if pctHistory[i] < pctHistory[minIdx] then minIdx = i end
- if pctHistory[i] > pctHistory[maxIdx] then maxIdx = i end
- end
- local currIdx = #pctHistory
- local function labelPoint(idx)
- local p = pctHistory[idx]
- local x = left + math.floor((offset + idx - 1) * gw / (HISTORY_MAX - 1) + 0.5)
- local y = bottom - math.floor((p / 100) * gh + 0.5)
- local lbl = string.format("%.1f%%", p)
- mon.setBackgroundColor(colors.black)
- mon.setTextColor(colors.white)
- mon.setCursorPos(x - math.floor(#lbl/2), y - 1)
- mon.write(lbl)
- end
- labelPoint(minIdx)
- labelPoint(maxIdx)
- labelPoint(currIdx)
- end
- -- Draw FE/t min/max/current labels (drawn LAST)
- local function drawFELabels(left, bottom, gw, gh, offset, vmin, vrange)
- if #feHistory == 0 then return end
- local minIdx, maxIdx = 1, 1
- for i = 2, #feHistory do
- if feHistory[i] < feHistory[minIdx] then minIdx = i end
- if feHistory[i] > feHistory[maxIdx] then maxIdx = i end
- end
- local currIdx = #feHistory
- local function labelPoint(idx)
- local v = feHistory[idx]
- local x = left + math.floor((offset + idx - 1) * gw / (HISTORY_MAX - 1) + 0.5)
- local t = (v - vmin) / vrange
- local y = bottom - math.floor(t * gh + 0.5)
- local lbl = string.format("%d", math.floor(v + 0.5))
- mon.setBackgroundColor(colors.black)
- mon.setTextColor(colors.white)
- mon.setCursorPos(x - math.floor(#lbl/2), y - 1)
- mon.write(lbl)
- end
- labelPoint(minIdx)
- labelPoint(maxIdx)
- labelPoint(currIdx)
- end
- -- Initialize display
- mon.setTextScale(0.5)
- mon.setBackgroundColor(colors.black)
- mon.clear()
- -- Main loop: sample at INTERVAL, redraw both graphs
- local timer = os.startTimer(INTERVAL)
- while true do
- local ev, id = os.pullEvent()
- if ev == "timer" and id == timer then
- local _, data = rednet.receive("generator_status")
- local fe = data.avgFEperTick or 0
- local pct = data.accPct or 0
- -- update histories
- table.insert(feHistory, fe)
- table.insert(pctHistory, pct)
- addTimestamp()
- if #feHistory > HISTORY_MAX then table.remove(feHistory, 1) end
- if #pctHistory > HISTORY_MAX then table.remove(pctHistory, 1) end
- -- draw background and get layout
- local left, top, right, bottom, gw, gh, vmin, vmax, vrange =
- drawBackground()
- -- draw graphs (no labels yet)
- drawPctGraph( left, top, right, bottom, gw, gh )
- drawFEGraph( left, top, right, bottom, gw, gh, vmin, vmax, vrange )
- -- draw all subpixel lines
- renderSubpixels(mon)
- -- draw min/max/current value labels last
- local offsetPct = HISTORY_MAX - #pctHistory
- drawPctLabels(left, bottom, gw, gh, offsetPct)
- local offsetFE = HISTORY_MAX - #feHistory
- drawFELabels(left, bottom, gw, gh, offsetFE, vmin, vrange)
- timer = os.startTimer(INTERVAL)
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement