CCCPaste

EnergyMonitor

-- CC:Tweaked + Advanced Peripherals
-- Monitors FE/t on one or two Energy Detectors (e.g., Mekanism Universal Cable)
-- Usage:
--   power_watch [inPeripheral] [outPeripheral] [intervalSeconds]
-- Examples:
--   power_watch                 -- auto-find two energyDetector peripherals if possible
--   power_watch inDet           -- only IN
--   power_watch left right 0.5  -- IN on left, OUT on right, 0.5s interval

local args = { ... }
local sample_interval = tonumber(args[3]) or 1.0

-- Helper: try to resolve a peripheral by exact name/side, else by type
local function resolveDetector(hint)
  if hint and peripheral.isPresent(hint) then
    local t = peripheral.getType(hint)
    if t == "energyDetector" then return peripheral.wrap(hint) end
  end
  return nil
end

-- Try resolve from args
local inDet = resolveDetector(args[1])
local outDet = resolveDetector(args[2])

-- If not provided, try to auto-find one or two detectors
if not inDet or (args[2] and not outDet) then
  local found = { peripheral.find("energyDetector") }
  if #found > 0 and not inDet then inDet = found[1] end
  if #found > 1 and not outDet then outDet = found[2] end
end

if not inDet and not outDet then
  print("Error: No energyDetector peripherals found.")
  print("Place Advanced Peripherals 'Energy Detector' blocks inline with your cable,")
  print("then attach the computer next to them or via wired modem. Label them if desired.")
  return
end

-- Optional monitor
local mon = peripheral.find("monitor")
if mon then
  mon.setTextScale(0.5)
  mon.setBackgroundColor(colors.black)
  mon.setTextColor(colors.white)
  mon.clear()
end

-- ring buffer for moving average
local function newAverager(n)
  local buf, sum, idx, count = {}, 0, 1, 0
  return {
    push = function(v)
      if count < n then
        count = count + 1
      else
        sum = sum - buf[idx]
      end
      buf[idx] = v
      sum = sum + v
      idx = (idx % n) + 1
    end,
    avg = function() return (count > 0) and (sum / count) or 0 end
  }
end

local avgIn  = newAverager(10)  -- ~10s avg at 1s interval
local avgOut = newAverager(10)

local cumInFE, cumOutFE = 0, 0  -- cumulative FE transferred (approx)
local lastTime = os.epoch("utc") / 1000.0

local function readFEt(det)
  if not det then return 0 end
  local ok, v = pcall(det.getTransferRate)
  if not ok or type(v) ~= "number" then return 0 end
  return v
end

local function draw(text)
  term.clear()
  term.setCursorPos(1,1)
  print(text)
  if mon then
    mon.clear()
    mon.setCursorPos(1,1)
    mon.write(("Power Watch @ %s"):format(textutils.formatTime(os.time(), true)))
    local lines = {}
    for line in text:gmatch("[^\n]+") do table.insert(lines, line) end
    for i=1,#lines do
      mon.setCursorPos(1, i+1)
      mon.write(lines[i])
    end
  end
end

local function fmtFE(v)
  -- human readable FE and FE/t
  local units = { {1e12, "T"}, {1e9,"G"}, {1e6,"M"}, {1e3,"k"} }
  for _,u in ipairs(units) do
    if math.abs(v) >= u[1] then return string.format("%.2f %s", v/u[1], u[2]) end
  end
  return string.format("%.0f", v)
end

while true do
  local now = os.epoch("utc") / 1000.0
  local dt = math.max(0.001, now - lastTime)
  lastTime = now

  local inFEt  = readFEt(inDet)
  local outFEt = readFEt(outDet)

  -- Push for moving average
  avgIn.push(inFEt)
  avgOut.push(outFEt)

  -- Integrate to cumulative FE (FE/t * seconds)
  cumInFE  = cumInFE  + inFEt  * dt
  cumOutFE = cumOutFE + outFEt * dt

  local lines = {}

  table.insert(lines, "=== CC:T Power Watch (Energy Detectors) ===")
  if inDet then
    table.insert(lines, string.format(
      "IN : %sFE/t (avg %sFE/t) | Total %sFE",
      fmtFE(inFEt), fmtFE(avgIn.avg()), fmtFE(cumInFE)
    ))
  else
    table.insert(lines, "IN : (not configured)")
  end

  if outDet then
    table.insert(lines, string.format(
      "OUT: %sFE/t (avg %sFE/t) | Total %sFE",
      fmtFE(outFEt), fmtFE(avgOut.avg()), fmtFE(cumOutFE)
    ))
  else
    table.insert(lines, "OUT: (not configured)")
  end

  table.insert(lines, string.format("Interval: %.2fs   Time: %s",
      sample_interval, textutils.formatTime(os.time(), true)))

  draw(table.concat(lines, "\n"))
  sleep(sample_interval)
end