Advertisement
zamoth

Untitled

Jul 5th, 2025 (edited)
209
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.87 KB | None | 0 0
  1. -- graph_ui.lua  (run on your graph‐UI computer)
  2.  
  3. -- Peripheral wrapping & term redirect
  4. rednet.open("left")
  5. local mon = assert(peripheral.wrap("monitor_4"), "Monitor not found")
  6. term.redirect(mon)
  7.  
  8. -- Configuration
  9. local HISTORY_MAX = 100    -- number of data points to keep
  10. local INTERVAL    = 1     -- seconds between samples
  11.  
  12. -- histories
  13. local feHistory  = {}
  14. local pctHistory = {}
  15.  
  16. -- Subpixel hi-res line helpers (2x2 per char cell)
  17. local subpixelGrid = {}
  18.  
  19. local function setSubpixel(gx, gy, col)
  20.   local cx = math.floor((gx-1)/2)+1
  21.   local cy = math.floor((gy-1)/2)+1
  22.   local sx = (gx-1)%2
  23.   local sy = (gy-1)%2
  24.   local bit = sy*2 + sx -- 0..3
  25.   subpixelGrid[cy] = subpixelGrid[cy] or {}
  26.   local cell = subpixelGrid[cy][cx] or {mask=0, col=col}
  27.   cell.mask = bit32.bor(cell.mask, bit32.lshift(1, bit))
  28.   cell.col = col or cell.col
  29.   subpixelGrid[cy][cx] = cell
  30. end
  31.  
  32. local function drawLine(x1, y1, x2, y2, col)
  33.   -- All coords are in normal monitor space; we'll scale up by 2 for subpixels
  34.   x1 = math.floor(x1 * 2 + 0.5)
  35.   y1 = math.floor(y1 * 2 + 0.5)
  36.   x2 = math.floor(x2 * 2 + 0.5)
  37.   y2 = math.floor(y2 * 2 + 0.5)
  38.   local dx = math.abs(x2 - x1)
  39.   local dy = math.abs(y2 - y1)
  40.   local sx = x1 < x2 and 1 or -1
  41.   local sy = y1 < y2 and 1 or -1
  42.   local err = dx - dy
  43.   while true do
  44.     setSubpixel(x1, y1, col)
  45.     if x1 == x2 and y1 == y2 then break end
  46.     local e2 = 2 * err
  47.     if e2 > -dy then err = err - dy; x1 = x1 + sx end
  48.     if e2 <  dx then err = err + dx; y1 = y1 + sy end
  49.   end
  50. end
  51.  
  52. local function renderSubpixels(mon)
  53.   for y, row in pairs(subpixelGrid) do
  54.     for x, cell in pairs(row) do
  55.       mon.setCursorPos(x, y)
  56.       mon.setTextColor(cell.col or colors.white)
  57.       mon.write(string.char(128 + (cell.mask or 0)))
  58.     end
  59.   end
  60.   mon.setTextColor(colors.white)
  61. end
  62.  
  63. local function clearSubpixels()
  64.   subpixelGrid = {}
  65. end
  66.  
  67. local function addTimestamp()
  68.   if not feHistory.timestamps then feHistory.timestamps = {} end
  69.   local t = textutils.formatTime(os.time(), true)
  70.   table.insert(feHistory.timestamps, t)
  71.   if #feHistory.timestamps > HISTORY_MAX then
  72.     table.remove(feHistory.timestamps, 1)
  73.   end
  74. end
  75.  
  76. -- Draw graph background (zero line as "_"), return layout + FE range
  77. local function drawBackground()
  78.   mon.setBackgroundColor(colors.black)
  79.   mon.clear()
  80.   clearSubpixels()
  81.  
  82.   local w, h = mon.getSize()
  83.   local left, top     = 3, 3
  84.   local right, bottom = w - 2, h - 2
  85.   local graph_w       = right - left
  86.   local graph_h       = bottom - top
  87.  
  88.   if #feHistory == 0 then
  89.     return left, top, right, bottom, graph_w, graph_h, 0, 1, 1
  90.   end
  91.  
  92.   -- compute FE history min/max including zero
  93.   local minV, maxV = feHistory[1], feHistory[1]
  94.   for i = 2, #feHistory do
  95.     local v = feHistory[i]
  96.     if v < minV then minV = v end
  97.     if v > maxV then maxV = v end
  98.   end
  99.   minV = math.min(minV, 0)
  100.   maxV = math.max(maxV, 0)
  101.   local range = maxV - minV
  102.  
  103.   -- draw horizontal zero line as subpixels (use gray)
  104.   local zero_t = (0 - minV) / range
  105.   local zero_y = bottom - math.floor(zero_t * graph_h + 0.5)
  106.   drawLine(left, zero_y, right, zero_y, colors.gray)
  107.  
  108.   -- draw fixed vertical grey bars and "seconds ago" labels at the bottom
  109.   local divisions = 10 -- number of spaces, so 10 bars (adjust as you want)
  110.   local labelRow = bottom + 1
  111.   local stepDiv = graph_w / divisions
  112.   for d = 0, divisions do
  113.     local x = left + math.floor(d * stepDiv + 0.5)
  114.     drawLine(x, top, x, bottom, colors.gray)
  115.     -- offset label in seconds ago
  116.     local secondsAgo = (divisions - d) * INTERVAL * math.floor(HISTORY_MAX / divisions)
  117.     mon.setCursorPos(x-2, labelRow)
  118.     mon.setTextColor(colors.lightGray)
  119.     mon.write("-" .. tostring(secondsAgo))
  120.     mon.setTextColor(colors.white)
  121.   end
  122.  
  123.   return left, top, right, bottom, graph_w, graph_h, minV, maxV, range
  124. end
  125.  
  126. -- Plot battery % graph in red (no labels here)
  127. local function drawPctGraph(left, top, right, bottom, gw, gh)
  128.   if #pctHistory == 0 then return end
  129.   local step   = gw / (HISTORY_MAX - 1)
  130.   local offset = HISTORY_MAX - #pctHistory
  131.  
  132.   local px, py
  133.   for i, p in ipairs(pctHistory) do
  134.     local x = left + math.floor((offset + i - 1) * step + 0.5)
  135.     local y = bottom - math.floor((p / 100) * gh + 0.5)
  136.     if px then drawLine(px, py, x, y, colors.red) end
  137.     px, py = x, y
  138.   end
  139. end
  140.  
  141. -- Plot FE/t graph in green (no labels here)
  142. local function drawFEGraph(left, top, right, bottom, gw, gh, vmin, vmax, vrange)
  143.   if #feHistory == 0 then return end
  144.   local step   = gw / (HISTORY_MAX - 1)
  145.   local offset = HISTORY_MAX - #feHistory
  146.  
  147.   local px, py
  148.   for i, v in ipairs(feHistory) do
  149.     local x = left + math.floor((offset + i - 1) * step + 0.5)
  150.     local t = (v - vmin) / vrange
  151.     local y = bottom - math.floor(t * gh + 0.5)
  152.     if px then drawLine(px, py, x, y, colors.lime) end
  153.     px, py = x, y
  154.   end
  155. end
  156.  
  157. -- Draw battery % min/max/current labels (drawn LAST)
  158. local function drawPctLabels(left, bottom, gw, gh, offset)
  159.   if #pctHistory == 0 then return end
  160.   local minIdx, maxIdx = 1, 1
  161.   for i = 2, #pctHistory do
  162.     if pctHistory[i] < pctHistory[minIdx] then minIdx = i end
  163.     if pctHistory[i] > pctHistory[maxIdx] then maxIdx = i end
  164.   end
  165.   local currIdx = #pctHistory
  166.   local function labelPoint(idx)
  167.     local p = pctHistory[idx]
  168.     local x = left + math.floor((offset + idx - 1) * gw / (HISTORY_MAX - 1) + 0.5)
  169.     local y = bottom - math.floor((p / 100) * gh + 0.5)
  170.     local lbl = string.format("%.1f%%", p)
  171.     mon.setBackgroundColor(colors.black)
  172.     mon.setTextColor(colors.white)
  173.     mon.setCursorPos(x - math.floor(#lbl/2), y - 1)
  174.     mon.write(lbl)
  175.   end
  176.   labelPoint(minIdx)
  177.   labelPoint(maxIdx)
  178.   labelPoint(currIdx)
  179. end
  180.  
  181. -- Draw FE/t min/max/current labels (drawn LAST)
  182. local function drawFELabels(left, bottom, gw, gh, offset, vmin, vrange)
  183.   if #feHistory == 0 then return end
  184.   local minIdx, maxIdx = 1, 1
  185.   for i = 2, #feHistory do
  186.     if feHistory[i] < feHistory[minIdx] then minIdx = i end
  187.     if feHistory[i] > feHistory[maxIdx] then maxIdx = i end
  188.   end
  189.   local currIdx = #feHistory
  190.   local function labelPoint(idx)
  191.     local v = feHistory[idx]
  192.     local x = left + math.floor((offset + idx - 1) * gw / (HISTORY_MAX - 1) + 0.5)
  193.     local t = (v - vmin) / vrange
  194.     local y = bottom - math.floor(t * gh + 0.5)
  195.     local lbl = string.format("%d", math.floor(v + 0.5))
  196.     mon.setBackgroundColor(colors.black)
  197.     mon.setTextColor(colors.white)
  198.     mon.setCursorPos(x - math.floor(#lbl/2), y - 1)
  199.     mon.write(lbl)
  200.   end
  201.   labelPoint(minIdx)
  202.   labelPoint(maxIdx)
  203.   labelPoint(currIdx)
  204. end
  205.  
  206. -- Initialize display
  207. mon.setTextScale(0.5)
  208. mon.setBackgroundColor(colors.black)
  209. mon.clear()
  210.  
  211. -- Main loop: sample at INTERVAL, redraw both graphs
  212. local timer = os.startTimer(INTERVAL)
  213. while true do
  214.   local ev, id = os.pullEvent()
  215.   if ev == "timer" and id == timer then
  216.     local _, data = rednet.receive("generator_status")
  217.     local fe  = data.avgFEperTick or 0
  218.     local pct = data.accPct        or 0
  219.  
  220.     -- update histories
  221.     table.insert(feHistory,  fe)
  222.     table.insert(pctHistory, pct)
  223.     addTimestamp()
  224.     if #feHistory  > HISTORY_MAX then table.remove(feHistory, 1)  end
  225.     if #pctHistory > HISTORY_MAX then table.remove(pctHistory, 1) end
  226.  
  227.     -- draw background and get layout
  228.     local left, top, right, bottom, gw, gh, vmin, vmax, vrange =
  229.       drawBackground()
  230.     -- draw graphs (no labels yet)
  231.     drawPctGraph( left, top, right, bottom, gw, gh )
  232.     drawFEGraph( left, top, right, bottom, gw, gh, vmin, vmax, vrange )
  233.     -- draw all subpixel lines
  234.     renderSubpixels(mon)
  235.     -- draw min/max/current value labels last
  236.     local offsetPct = HISTORY_MAX - #pctHistory
  237.     drawPctLabels(left, bottom, gw, gh, offsetPct)
  238.     local offsetFE = HISTORY_MAX - #feHistory
  239.     drawFELabels(left, bottom, gw, gh, offsetFE, vmin, vrange)
  240.  
  241.     timer = os.startTimer(INTERVAL)
  242.   end
  243. end
  244.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement