Archives
Trending
Support
Login
clear text
XML
Django
JavaScript
MATLAB
C
C++
C#
Python
SQL
Shell
Bash
Markdown
YAML
JSON
HTML
CSS
PHP
Java
Ruby
Go
Rust
Swift
Kotlin
Arduino
TypeScript
Perl
Autohotkey
Lua
SQF
R
Scala
Haskell
Groovy
Dart
Clojure
VB.NET
Objective-C
PowerShell
Bash
CoffeeScript
Verilog
-- fission_agent.lua -- per-reactor agent for Mekanism fission (CC:T) -- needs: ldb2, rnc2 -- hard safety: SCRAM >= 1400 C, never start >= 1000 C os.loadAPI("ldb2") os.loadAPI("rnc2") local PROG = "fission-agent" local MY_ID = rnc2.getId(PROG) print("my id:", MY_ID) -- timings local HEARTBEAT_EVERY = 1.0 -- seconds local CONTROLLER_TIMEOUT = 5.0 -- seconds -- temps (hard rules) local HARD_SCRAM_TEMP = 1400 -- >= this -> scram, unoverrideable local SAFE_START_TEMP = 1000 -- must be lower than this to activate/start -- "soft" safety defaults (controller may disable these) local SOFT_MIN_COOLANT = 5 -- % if coolant below -> soft scram local SOFT_MAX_WASTE = 95 -- % if waste above -> soft scram local SOFT_MAX_HOT = 95 -- % if heated-coolant above -> soft scram -- find the fission reactor logic adapter local reactor = peripheral.find("fissionReactorLogicAdapter") if not reactor then error("fission_agent: no fissionReactorLogicAdapter found") end -- state local controllerId = nil local controllerLastSeen = 0 local softAutoScram = true -- controller can toggle this, but NOT the 1400C rule local lastHeartbeat = 0 -- helpers ------------------------------------------------- local function safe(fn, ...) if not fn then return nil end local ok, res = pcall(fn, ...) if ok then return res else return nil end end local function scram() -- fission has scram() if reactor.scram then reactor.scram() end -- also zero burn to be sure if reactor.setBurnRate then reactor.setBurnRate(0) end end local function canStartNow() local temp = safe(reactor.getTemperature) or 0 return temp < SAFE_START_TEMP end local function start() if not canStartNow() then -- too hot, ignore start return false end if reactor.activate then reactor.activate() end return true end local function setBurn(b) b = tonumber(b) or 0 if not canStartNow() then -- refuse to set high burn while hot, but do allow 0 if b > 0 then return false, "too hot" end end local maxB = safe(reactor.getMaxBurnRate) or b if b > maxB then b = maxB end if b < 0 then b = 0 end if reactor.setBurnRate then reactor.setBurnRate(b) end return true, b end -- telemetry using ONLY your methods ----------------------- local function readTelemetry() local temp = safe(reactor.getTemperature) or 0 local burn = safe(reactor.getBurnRate) or 0 local actualBurn = safe(reactor.getActualBurnRate) or burn local coolPct = safe(reactor.getCoolantFilledPercentage) or 0 local hotPct = safe(reactor.getHeatedCoolantFilledPercentage) or 0 local fuelPct = safe(reactor.getFuelFilledPercentage) or 0 local wastePct = safe(reactor.getWasteFilledPercentage) or 0 local heating = safe(reactor.getHeatingRate) or 0 local status = safe(reactor.getStatus) or "unknown" local formed = safe(reactor.isFormed) or false local forced = safe(reactor.isForceDisabled) or false return { id = MY_ID, temp = temp, burn = burn, actualBurn = actualBurn, coolantPct = coolPct, heatedCoolantPct = hotPct, fuelPct = fuelPct, wastePct = wastePct, heatingRate = heating, status = status, formed = formed, forceDisabled = forced, softAutoScram = softAutoScram, time = os.epoch("utc"), } end -- decide soft-unsafe from telemetry local function isSoftUnsafe(telem) if not softAutoScram then return false end if telem.coolantPct and telem.coolantPct > 0 and telem.coolantPct < SOFT_MIN_COOLANT then return true end if telem.wastePct and telem.wastePct >= SOFT_MAX_WASTE then return true end if telem.heatedCoolantPct and telem.heatedCoolantPct >= SOFT_MAX_HOT then return true end return false end -- message handling ----------------------------------------- local function handleMessage(pkt) if rnc2.autoPong(PROG, pkt) then return end local b = pkt.body or {} local t = b.type -- controller discovery if t == "discover" or t == "controller-hello" then controllerId = pkt.from controllerLastSeen = os.clock() if b.disableSoftScram ~= nil then softAutoScram = not b.disableSoftScram end -- answer rnc2.send(PROG, pkt.from, { type = "reactor-hello", id = MY_ID, role = "fission-reactor", telem = readTelemetry(), ver = "fission_agent/1.1" }) return end -- controller heartbeat if t == "controller-hb" then controllerId = pkt.from controllerLastSeen = os.clock() if b.disableSoftScram ~= nil then softAutoScram = not b.disableSoftScram end return end -- direct commands if t == "cmd" then controllerId = pkt.from controllerLastSeen = os.clock() if b.cmd == "on" then local ok = start() rnc2.send(PROG, pkt.from, { type="ack", cmd="on", ok=ok, reason= ok and nil or "temp>=1000" }) elseif b.cmd == "off" then scram() rnc2.send(PROG, pkt.from, { type="ack", cmd="off", ok=true }) elseif b.cmd == "setBurn" and b.value then local ok, valOrReason = setBurn(b.value) if ok then rnc2.send(PROG, pkt.from, { type="ack", cmd="setBurn", ok=true, burn=valOrReason }) else rnc2.send(PROG, pkt.from, { type="ack", cmd="setBurn", ok=false, reason=valOrReason }) end elseif b.cmd == "setSoftScram" and b.value ~= nil then softAutoScram = b.value and true or false rnc2.send(PROG, pkt.from, { type="ack", cmd="setSoftScram", ok=true, softAutoScram=softAutoScram }) end end end -- main loop ------------------------------------------------ print("fission_agent started, id=" .. MY_ID) while true do local now = os.clock() -- controller timeout -> re-enable soft scram if controllerId and (now - controllerLastSeen) > CONTROLLER_TIMEOUT then controllerId = nil softAutoScram = true print("controller lost -> soft auto-scram re-enabled") end -- get telemetry (once per tick) local telem = readTelemetry() -- HARD safety (cannot be disabled) if telem.temp and telem.temp >= HARD_SCRAM_TEMP then if telem.status ~= "stopped" then print(("HARD SCRAM at %.1f C"):format(telem.temp)) scram() end else -- SOFT safety (controller can disable) if isSoftUnsafe(telem) then if telem.status ~= "stopped" then print("SOFT SCRAM (coolant/waste/hot)") scram() end end end -- Heartbeat (1/s) if (now - lastHeartbeat) >= HEARTBEAT_EVERY then lastHeartbeat = now local hb = { type = "hb", id = MY_ID, role = "fission-reactor", telem = telem } if controllerId then rnc2.send(PROG, controllerId, hb) else rnc2.broadcast(PROG, hb) end end -- non-blocking recv local pkt = rnc2.recv(PROG, 0.2) if pkt then handleMessage(pkt) end end
Mark as private (unlisted)
for 30 minutes
for 6 hours
for 1 day
for 1 week
for 1 month
for 1 year
everlasting (like CCCP)