<% local sys = require "luci.sys" local http = require "luci.http" local uci = require "luci.model.uci".cursor() local function to_bytes(value, unit) local m = { KiB=1024, MiB=1048576, GiB=1073741824, TiB=1099511627776 } return tonumber(value) * (m[unit] or 1) end local function format_date(date_str) local months = {"Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec"} local mo, d, y = date_str:match("(%d%d)/(%d%d)/(%d%d)") if mo and d and y then return string.format("%02d %s %02d", tonumber(d), months[tonumber(mo)], tonumber(y)) end return date_str end local function today_label() return os.date("%d %b %y") end local function curmonth_label() return os.date("%b '%y") end local function ensure_today(stats) local lbl = today_label() for _, s in ipairs(stats) do if s.date == lbl then return stats end end table.insert(stats, { date=lbl, rx=0, tx=0 }) return stats end local function ensure_curmonth(stats) local lbl = curmonth_label() for _, s in ipairs(stats) do if s.month == lbl then return stats end end table.insert(stats, { month=lbl, rx=0, tx=0 }) return stats end local function get_interfaces() local ifaces = {} local p = io.popen("ls /etc/vnstat/ 2>/dev/null | grep -v '.conf$' | grep -v '.old$'") if p then for iface in p:lines() do iface = iface:match("^%s*(.-)%s*$") if iface ~= "" then table.insert(ifaces, iface) end end p:close() end table.sort(ifaces) return ifaces end local function get_daily_stats(iface) local stats = {} local out = sys.exec("vnstat -i " .. iface .. " --days 2>/dev/null") or "" for date, rx_v, rx_u, tx_v, tx_u in out:gmatch("(%d%d/%d%d/%d%d)%s+([%d%.]+)%s+([KMGT]iB)%s+|%s+([%d%.]+)%s+([KMGT]iB)") do table.insert(stats, { date = format_date(date), rx = to_bytes(rx_v, rx_u), tx = to_bytes(tx_v, tx_u) }) end return ensure_today(stats) end local function get_monthly_stats(iface) local stats = {} local out = sys.exec("vnstat -i " .. iface .. " --months 2>/dev/null") or "" for month, rx_v, rx_u, tx_v, tx_u in out:gmatch("(%a+%s+'%d%d)%s+([%d%.]+)%s+([KMGT]iB)%s+|%s+([%d%.]+)%s+([KMGT]iB)") do table.insert(stats, { month = month, rx = to_bytes(rx_v, rx_u), tx = to_bytes(tx_v, tx_u) }) end return ensure_curmonth(stats) end local function fmt_bytes(v) if v >= 1099511627776 then return string.format("%.2f TB", v/1099511627776) elseif v >= 1073741824 then return string.format("%.2f GB", v/1073741824) elseif v >= 1048576 then return string.format("%.2f MB", v/1048576) elseif v >= 1024 then return string.format("%.2f KB", v/1024) end return tostring(v) .. " B" end local ifaces = get_interfaces() local saved_iface = uci:get("netstats", "@config[0]", "prefer") or "" local saved_mode = uci:get("netstats", "@config[0]", "mode") or "daily" local cur_iface = http.formvalue("iface") or saved_iface or ifaces[1] or "" local view_mode = http.formvalue("mode") or saved_mode if view_mode ~= "daily" and view_mode ~= "monthly" then view_mode = "daily" end local stats, title = {}, "" if cur_iface ~= "" then if view_mode == "monthly" then stats = get_monthly_stats(cur_iface) title = translate("Monthly") else stats = get_daily_stats(cur_iface) title = translate("Daily") end end local total_rx, total_tx = 0, 0 for _, s in ipairs(stats) do total_rx = total_rx + (s.rx or 0) total_tx = total_tx + (s.tx or 0) end %>

<%:Usage is displayed using the Interface and View Mode selected in the Settings tab.%>

<% if cur_iface ~= "" and #stats > 0 then %>
<%:Download%>: <%=fmt_bytes(total_rx)%>
<%:Upload%>: <%=fmt_bytes(total_tx)%>
<%:Total%>: <%=fmt_bytes(total_rx + total_tx)%>

<%=title%> <%:Usage%>

<%=cur_iface%>
<% elseif #ifaces == 0 then %>
📡 <%:No vnStat interfaces were found. Make sure vnStat has been initialized.%>
<% else %>
📊 <%:No data available for%> <%=cur_iface%>
<%:vnStat may still be collecting its first data. Try again in a few minutes.%>
<% end %>