Skip to content

Instantly share code, notes, and snippets.

@vshymanskyy
Last active October 12, 2024 10:13
Show Gist options
  • Save vshymanskyy/3d3388a4e17f440a7cf543ade039c62c to your computer and use it in GitHub Desktop.
Save vshymanskyy/3d3388a4e17f440a7cf543ade039c62c to your computer and use it in GitHub Desktop.
#!/usr/bin/env lua
local socket = require("socket")
local use_ssl, ssl = pcall(require, "ssl")
local Blynk = require("blynk.socket")
local Timer = require("timer")
local http = require("socket.http")
assert(#arg >= 1, "Please specify Auth Token")
local auth = arg[1]
local blynk = Blynk.new(auth, {
heartbeat = 50,
-- log = print,
})
function exec_out(cmd)
local file = io.popen(cmd)
if not file then return nil end
local data = file:read("*a")
file:close()
-- print("Run: "..cmd.." -> "..data)
return data
end
function read_file(path)
local file = io.open(path, "rb")
if not file then return nil end
local data = file:read("*a")
file:close()
-- print("Read: "..path.." -> "..data)
return data
end
function getArpClients()
return tonumber(exec_out("cat /proc/net/arp | grep br-lan | grep 0x2 | wc -l"))
end
function getUptime()
return tonumber(exec_out("cat /proc/uptime | awk '{print $1}'"))
end
function getPublicIP()
local body, code, headers, status = http.request("https://api.ipify.org")
if code == 200 then
return body
end
return ""
end
function getHddSpinning()
local code = os.execute("smartctl --nocheck=standby --info /dev/sda > /dev/null")
return (code == 0) and 1 or 0
end
function getHddStats()
local out = exec_out("cat /proc/diskstats | grep 'sda ' | awk '{print $6, $10}'")
local reads, writes = out:match("([^ ]+) +([^ ]+)")
return reads, writes
end
function getCpuLoad()
return tonumber(exec_out("top -bn1 | grep 'CPU:' | head -n1 | awk '{print $2+$4}'"))
end
function getRamUsage()
return tonumber(exec_out("free | grep Mem | awk '{print ($2-$4)/$2 * 100.0}'"))
end
function getWanIF()
return exec_out("source /lib/functions/network.sh; network_flush_cache; network_find_wan NET_IF; echo -n $NET_IF")
end
function getWanIP()
local wanif = getWanIF()
if wanif == "" then return "" end
return exec_out("source /lib/functions/network.sh; network_get_ipaddr NET_ADDR " .. wanif .. "; echo $NET_ADDR")
end
function getWanRxBytes()
local wanif = getWanIF()
if wanif == "" then return 0 end
return tonumber(read_file("/sys/class/net/" .. wanif .. "/statistics/rx_bytes"))
end
function getWanTxBytes()
local wanif = getWanIF()
if wanif == "" then return 0 end
return tonumber(read_file("/sys/class/net/" .. wanif .. "/statistics/tx_bytes"))
end
function getActiveConnections()
return tonumber(read_file("/proc/sys/net/netfilter/nf_conntrack_count"))
end
function getWiFiStatus()
if string.find(exec_out("ubus call network.wireless status | jsonfilter -e '@.radio0.up'"), "true") then
return 1
else
return 0
end
end
local function connectBlynk()
local host = "blynk.cloud"
local sock = assert(socket.tcp())
sock:setoption("tcp-nodelay", true)
if use_ssl then
print("Connecting Blynk (secure)...")
sock:connect(host, 443)
local opts = {
mode = "client",
protocol = "tlsv1_2"
}
sock = assert(ssl.wrap(sock, opts))
sock:dohandshake()
else
print("Connecting Blynk...")
sock:connect(host, 80)
end
-- tell Blynk to use this socket
blynk:connect(sock)
end
--[[ WiFi control ]]
blynk:on("V20", function(param)
if param[1] == "1" then
os.execute("wifi up")
else
os.execute("wifi down")
end
end)
--[[ Locking ]]
local isLocked = true
local function advLock()
blynk:setProperty(30,"color","#D3435C") -- red
blynk:setProperty(30,"label","Locked")
isLocked = true
end
local function advUnlock()
blynk:setProperty(30,"color","#23C48E") -- green
blynk:setProperty(30,"label","Unlocked")
isLocked = false
end
blynk:on("V30", function(param)
if isLocked and param[1] == "10" then
advUnlock()
elseif not isLocked then
advLock()
end
end)
--[[ Reboot ]]
blynk:on("internal:dbg", function(param)
if param[1] == "reboot" then
os.execute("reboot")
end
end)
--[[ Shell ]]
blynk:on("V35", function(param)
if isLocked then
blynk:virtualWrite(35, "Shell is LOCKED\n")
return
end
local out = exec_out(param[1])
blynk:virtualWrite(35, out)
end)
blynk:on("disconnected", function()
print("Disconnected.")
-- auto-reconnect after 5 seconds
socket.sleep(5)
connectBlynk()
end)
--[[ Timers ]]
local prev = { spin = -1 }
local tmr1 = Timer:new{interval = 5000, func = function()
local tx = getWanTxBytes()
local rx = getWanRxBytes()
if prev.tx then
local dtx = tx - prev.tx
if prev.dtx ~= dtx then
blynk:virtualWrite(1, dtx / 1024 / 1024)
prev.dtx = dtx
end
end
prev.tx = tx
if prev.rx and prev.rx ~= rx then
local drx = rx - prev.rx
if prev.drx ~= drx then
blynk:virtualWrite(2, drx / 1024 / 1024)
prev.drx = drx
end
end
prev.rx = rx
local spin = getHddSpinning()
if spin ~= prev.spin then
blynk:virtualWrite(7, spin)
end
prev.spin = spin
if spin then
local rd, wt = getHddStats()
if prev.rd then
local drd = rd - prev.rd
if prev.drd ~= drd then
blynk:virtualWrite(8, drd)
prev.drd = drd
end
end
prev.rd = rd
if prev.wt then
local dwt = wt - prev.wt
if prev.dwt ~= dwt then
blynk:virtualWrite(9, dwt)
prev.dwt = dwt
end
end
prev.wt = wt
end
blynk:virtualWrite(4, getActiveConnections())
blynk:virtualWrite(5, getCpuLoad())
blynk:virtualWrite(6, getRamUsage())
blynk:virtualWrite(10, getArpClients())
end}
local tmr2 = Timer:new{interval = 5*60*1000, func = function()
blynk:virtualWrite(11, string.format("%.1f", getUptime()/60/60))
end}
blynk:on("connected", function(ping)
print("Ready. Ping: " .. math.floor(ping*1000) .. "ms")
blynk:virtualWrite(12, getWanIP())
blynk:virtualWrite(13, getPublicIP())
blynk:virtualWrite(20, getWiFiStatus())
end)
connectBlynk()
while true do
blynk:run()
tmr1:run()
tmr2:run()
end
@liger1978
Copy link

This is more reliable for getting the current WAN IP address:

function getWanIP()
  return exec_out("source /lib/functions/network.sh; network_flush_cache; network_find_wan NET_IF; network_get_ipaddr NET_ADDR $NET_IF; echo $NET_ADDR")
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment