Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- controller.lua
- -- shows reactors, lets you start/stop, and has a yellow "RESTART ALL" button
- -- clicks work on:
- -- - ADVANCED monitor (monitor_touch)
- -- - controller PC screen (mouse_click)
- os.loadAPI("rnc3")
- local CTRL_PROG = "fission-controller"
- local AGENT_PROG = "fission-agent"
- local CTRL_ID = rnc3.getId(CTRL_PROG)
- local CTRL_PORT = rnc3.getPort(CTRL_PROG)
- local AGENT_PORT = rnc3.getPort(AGENT_PROG)
- local DISCOVER_EVERY = 3
- local REDRAW_EVERY = 0.4
- local OFFLINE_AFTER = 10
- -- logging ---------------------------------------------------
- local function log(msg)
- local h = fs.open("debug.log", "a")
- h.writeLine(("[%d] %s"):format(os.epoch("utc"), msg))
- h.close()
- end
- log("=== controller start ===")
- log(("CTRL_ID=%s CTRL_PORT=%d AGENT_PORT=%d"):format(CTRL_ID, CTRL_PORT, AGENT_PORT))
- -- open both ports on all modems
- do
- local ms = { peripheral.find("modem") }
- for _, m in ipairs(ms) do
- if not m.isOpen(CTRL_PORT) then m.open(CTRL_PORT) end
- if not m.isOpen(AGENT_PORT) then m.open(AGENT_PORT) end
- end
- end
- -- monitor ---------------------------------------------------
- local mon = peripheral.find("monitor")
- if not mon then error("no monitor") end
- -- pick small-ish scale
- for _, s in ipairs({1, 0.75, 0.5, 0.25}) do
- mon.setTextScale(s)
- local w,h = mon.getSize()
- if h >= 4 then break end
- end
- mon.setBackgroundColor(colors.black)
- mon.setTextColor(colors.white)
- mon.clear()
- -- state -----------------------------------------------------
- local reactors = {} -- [id] = {id=..., telem=..., lastSeen=..., row=...}
- local lastDiscover = 0
- local lastDraw = 0
- -- UI coords -------------------------------------------------
- local function shortId(id, max)
- max = max or 12
- if #id <= max then return id end
- return id:sub(1, max-3) .. "..."
- end
- -- will update every draw
- local restartBtn = {x1=1, x2=1, y=1}
- local function draw()
- local w,h = mon.getSize()
- mon.setBackgroundColor(colors.black)
- mon.setTextColor(colors.white)
- mon.clear()
- -- top bar: center "RESTART ALL" in yellow
- local label = "RESTART ALL"
- local x1 = math.floor((w - #label)/2) + 1
- local x2 = x1 + #label - 1
- restartBtn.x1 = x1
- restartBtn.x2 = x2
- restartBtn.y = 1
- mon.setCursorPos(x1, 1)
- mon.setTextColor(colors.yellow)
- mon.write(label)
- -- list reactors
- local list = {}
- for _, r in pairs(reactors) do table.insert(list, r) end
- table.sort(list, function(a,b) return a.id < b.id end)
- local row = 2
- local drawn = 0
- for _, r in ipairs(list) do
- if row > h then break end
- local online = (os.clock() - r.lastSeen) < OFFLINE_AFTER
- local t = r.telem or {}
- local temp = t.temp or 0
- local burn = t.burn or 0
- -- ✅ running = burn > 0
- local running = (burn and burn > 0)
- r.row = row
- mon.setCursorPos(1, row)
- if online then mon.setTextColor(colors.white) else mon.setTextColor(colors.gray) end
- local btnText = running and "[OFF]" or "[ON]"
- local idPart = shortId(r.id, math.floor(w*0.35))
- local tempPart = (" T:%d"):format(temp)
- local burnPart = (" B:%d"):format(burn)
- local text = idPart .. tempPart .. burnPart
- local maxText = w - #btnText
- if #text > maxText then text = text:sub(1, maxText) end
- mon.write(text)
- local btnX = w - #btnText + 1
- if btnX < 1 then btnX = 1 end
- mon.setCursorPos(btnX, row)
- if running then mon.setTextColor(colors.red) else mon.setTextColor(colors.lime) end
- mon.write(btnText)
- drawn = drawn + 1
- row = row + 1
- end
- log(("draw: %d reactors, %d shown, mon=%dx%d"):format(#list, drawn, w, h))
- end
- local function reactorAtY(y)
- for _, r in pairs(reactors) do
- if r.row == y then return r end
- end
- return nil
- end
- local function sendDiscover()
- rnc3.send(CTRL_PROG, "*", {type="discover", disableSoftScram=true})
- log("sent discover")
- end
- local function sendControllerHB()
- for id,_ in pairs(reactors) do
- rnc3.send(CTRL_PROG, id, {type="controller-hb", disableSoftScram=true})
- end
- end
- local function handlePacket(pkt, viaPort)
- local b = pkt.body or {}
- local t = b.type
- if t == "reactor-hello" or t == "hb" then
- local rid = pkt.from
- if not reactors[rid] then
- reactors[rid] = { id = rid }
- log("new reactor: " .. rid)
- end
- reactors[rid].lastSeen = os.clock()
- reactors[rid].telem = b.telem or reactors[rid].telem
- -- keep them alive
- rnc3.send(CTRL_PROG, rid, {type="controller-hb", disableSoftScram=true})
- end
- end
- -- action ----------------------------------------------------
- local function toggleReactor(r)
- local t = r.telem or {}
- local burn = t.burn or 0
- local running = burn > 0
- if running then
- log("send OFF -> " .. r.id)
- rnc3.send(CTRL_PROG, r.id, {type="cmd", cmd="off"})
- else
- log("send ON -> " .. r.id)
- rnc3.send(CTRL_PROG, r.id, {type="cmd", cmd="on"})
- end
- end
- local function restartAll()
- log("RESTART ALL pressed")
- for id,_ in pairs(reactors) do
- rnc3.send(CTRL_PROG, id, {type="cmd", cmd="restart"})
- end
- end
- -- main loop ------------------------------------------------
- while true do
- local now = os.clock()
- if now - lastDiscover >= DISCOVER_EVERY then
- sendDiscover()
- lastDiscover = now
- end
- if now - lastDraw >= REDRAW_EVERY then
- draw()
- lastDraw = now
- end
- local ev,p1,p2,p3,p4,p5 = os.pullEvent()
- if ev == "modem_message" then
- local channel = p2
- local data = p4
- if channel == CTRL_PORT or channel == AGENT_PORT then
- local ok,pkt = pcall(textutils.unserialize, data)
- if ok and type(pkt) == "table" then
- if (not pkt.to) or pkt.to == "*" or pkt.to == CTRL_ID then
- handlePacket(pkt, channel)
- lastDraw = 0
- end
- end
- end
- elseif ev == "monitor_touch" then
- local side,x,y = p1,p2,p3
- log(("monitor_touch x=%d y=%d"):format(x,y))
- -- top button?
- if y == restartBtn.y and x >= restartBtn.x1 and x <= restartBtn.x2 then
- restartAll()
- else
- local r = reactorAtY(y)
- if r then toggleReactor(r) end
- end
- lastDraw = 0
- elseif ev == "mouse_click" then
- -- clicking in controller PC terminal
- local button,x,y = p1,p2,p3
- log(("mouse_click x=%d y=%d"):format(x,y))
- if y == restartBtn.y and x >= restartBtn.x1 and x <= restartBtn.x2 then
- restartAll()
- else
- local r = reactorAtY(y)
- if r then toggleReactor(r) end
- end
- lastDraw = 0
- elseif ev == "terminate" then
- log("terminated")
- mon.clear()
- mon.setCursorPos(1,1)
- mon.write("CTRL stopped")
- break
- end
- sendControllerHB()
- end
Advertisement
Add Comment
Please, Sign In to add comment