mirror of https://github.com/aredn/aredn.git
Old version - now in mgr/snrlog.lua (#339) 04/22/2022
This commit is contained in:
parent
c42ac68767
commit
c83cef5928
|
@ -1,441 +0,0 @@
|
|||
#!/usr/bin/lua
|
||||
--[[
|
||||
|
||||
Part of AREDN -- Used for creating Amateur Radio Emergency Data Networks
|
||||
Copyright (C) 2019 Darryl Quinn
|
||||
See Contributors file for additional contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation version 3 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional Terms:
|
||||
|
||||
Additional use restrictions exist on the AREDN(TM) trademark and logo.
|
||||
See AREDNLicense.txt for more info.
|
||||
|
||||
Attributions to the AREDN Project must be retained in the source code.
|
||||
If importing this code into a new or existing project attribution
|
||||
to the AREDN project must be added to the source code.
|
||||
|
||||
You must not misrepresent the origin of the material contained within.
|
||||
|
||||
Modified versions must be modified to attribute to the original source
|
||||
and be marked in reasonable ways as differentiate it from the original
|
||||
version
|
||||
|
||||
--]]
|
||||
|
||||
require("aredn.utils")
|
||||
local aredn_info=require("aredn.info")
|
||||
require("uci")
|
||||
require("aredn.uci")
|
||||
local nxo=require("nixio")
|
||||
require("iwinfo")
|
||||
require("luci.sys")
|
||||
|
||||
|
||||
-- setup extensions
|
||||
os.capture=capture
|
||||
string.print=print_r
|
||||
|
||||
|
||||
-- delay just after rssi_monitor has a chance to run noise floor calibration
|
||||
local MAXLINES=2880 -- 2 days worth
|
||||
local AGETIME=43200
|
||||
local INACTIVETIMEOUT=10000
|
||||
local tmpdir="/tmp/snrlog"
|
||||
local lastdat="/tmp/snr.dat"
|
||||
local autolog="/tmp/AutoDistReset.log"
|
||||
local lasttime={}
|
||||
local lines={}
|
||||
local arpcache={}
|
||||
local nscache={}
|
||||
local defnoise=-95
|
||||
local tmpdirlist={}
|
||||
local neighbors={}
|
||||
local stations={}
|
||||
local wifiiface=""
|
||||
local bandwidth=""
|
||||
local nulledout={}
|
||||
local pidfile="/tmp/snrlog.pid"
|
||||
local rssifile="/tmp/rssi_monitor.pid"
|
||||
|
||||
-- Neighbor Class
|
||||
Neighbor={}
|
||||
Neighbor.__index=Neighbor
|
||||
function Neighbor.create(macaddress)
|
||||
local n={}
|
||||
setmetatable(n,Neighbor)
|
||||
n.mac=macaddress:lower()
|
||||
n.hostname=nil
|
||||
n.sigfile=nil
|
||||
n.datafile=nil
|
||||
n.ip=nil
|
||||
n.lastseen=nil
|
||||
n.level=nil
|
||||
|
||||
n.ip=n:findIp()
|
||||
n.hostname=n:findHostname()
|
||||
n.signal=n:findSignal() or ""
|
||||
n.noise=n:findNoise() or ""
|
||||
n.tx_mcs=n:findTxMcs() or ""
|
||||
n.tx_rate=n:findTxRate() or ""
|
||||
n.rx_mcs=n:findRxMcs() or ""
|
||||
n.rx_rate=n:findRxRate() or ""
|
||||
n.lastseen=n:findLastTime() or now
|
||||
-- check if auto-distance reset is required (new node)
|
||||
local efn=n:getExistingDataFileName()
|
||||
if efn==nil or ((now-n.lastseen) > 100) then -- NEW or not recently seen node
|
||||
reset_auto_distance()
|
||||
f, err=assert(io.open(autolog, "a"),"Cannot open file (autolog) to write!")
|
||||
if (f) then
|
||||
f:write(now .. "\n")
|
||||
f:close()
|
||||
end
|
||||
file_trim(autolog,MAXLINES)
|
||||
end
|
||||
|
||||
n.datafile=n:generateDataFileName()
|
||||
return n
|
||||
end
|
||||
|
||||
function Neighbor:hasIP()
|
||||
return not (self.ip==nil)
|
||||
end
|
||||
|
||||
function Neighbor:hasHostName()
|
||||
return not (self.hostname==nil)
|
||||
end
|
||||
|
||||
function Neighbor:getExistingDataFileName()
|
||||
local efn=nil
|
||||
for fn in nxo.fs.glob(tmpdir.."/"..self.mac.."-*") do
|
||||
efn=nxo.fs.basename(fn)
|
||||
end
|
||||
return efn
|
||||
end
|
||||
|
||||
function Neighbor:generateDataFileName()
|
||||
local tmpfn=nil
|
||||
local efn=self:getExistingDataFileName()
|
||||
if efn~=nil then
|
||||
-- existing file found, improve or use
|
||||
tmpfn=self.mac.."-"
|
||||
m,x=string.match(efn,"^([%x2:]*)%-(.*)")
|
||||
if x==nil or x=="" then -- "00:11:22:33:44:55-"
|
||||
if self:hasHostName() then
|
||||
tmpfn=tmpfn..self.hostname
|
||||
nxo.fs.rename(tmpdir.."/"..efn,tmpdir.."/"..tmpfn)
|
||||
elseif self:hasIP() then
|
||||
tmpfn=tmpfn..self.ip
|
||||
nxo.fs.rename(tmpdir.."/"..efn,tmpdir.."/"..tmpfn)
|
||||
end
|
||||
elseif get_ip_type(x)==1 then -- "00:11:22:33:44:55-10.11.22.33"
|
||||
if self:hasHostName() then
|
||||
tmpfn=tmpfn..self.hostname
|
||||
nxo.fs.rename(tmpdir.."/"..efn,tmpdir.."/"..tmpfn)
|
||||
else
|
||||
tmpfn=efn
|
||||
end
|
||||
else -- "00:11:22:33:44:55-MAYBE-GOOD-HOST"
|
||||
if x==self.hostname then -- "00:11:22:33:44:55-SAME-HOST"
|
||||
tmpfn=efn
|
||||
else -- "00:11:22:33:44:55-NEW-HOST-NAME"
|
||||
if self.hostname~=nil then
|
||||
tmpfn=tmpfn..self.hostname
|
||||
nxo.fs.rename(tmpdir.."/"..efn,tmpdir.."/"..tmpfn)
|
||||
else
|
||||
tmpfn=efn
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
-- no prior file, let's generate one
|
||||
tmpfn=self.mac.."-"
|
||||
if self:hasHostName() then
|
||||
tmpfn=tmpfn..self.hostname
|
||||
elseif self:hasIP() then
|
||||
tmpfn=tmpfn..self.ip
|
||||
end
|
||||
end
|
||||
return tmpfn
|
||||
end
|
||||
|
||||
function Neighbor:findLastTime()
|
||||
self.lastseen=lasttime[mac]
|
||||
return self.lastseen
|
||||
end
|
||||
|
||||
function Neighbor:findHostname()
|
||||
if self:hasIP() then
|
||||
self.hostname=nslookup(self.ip)
|
||||
end
|
||||
return self.hostname
|
||||
end
|
||||
|
||||
function Neighbor:findIp()
|
||||
-- lookup IP from arpcache
|
||||
local myarp=arpcache[self.mac]
|
||||
if myarp~=nil then
|
||||
self.ip=myarp["IP address"]
|
||||
end
|
||||
return self.ip
|
||||
end
|
||||
|
||||
function Neighbor:findSignal()
|
||||
-- lookup from iwinfo
|
||||
self.signal=stations[self.mac:upper()].signal
|
||||
return self.signal
|
||||
end
|
||||
|
||||
function Neighbor:findNoise()
|
||||
-- lookup from iwinfo
|
||||
self.noise=stations[self.mac:upper()].noise
|
||||
return self.noise
|
||||
end
|
||||
|
||||
function Neighbor:findTxMcs()
|
||||
self.tx_mcs=stations[self.mac:upper()].tx_mcs or -1
|
||||
return self.tx_mcs
|
||||
end
|
||||
|
||||
function Neighbor:findTxRate()
|
||||
local r=(stations[self.mac:upper()].tx_rate)/1000
|
||||
self.tx_rate=adjust_rate(r,bandwidth)
|
||||
return self.tx_rate
|
||||
end
|
||||
|
||||
function Neighbor:findRxMcs()
|
||||
self.rx_mcs=stations[self.mac:upper()].rx_mcs or -1
|
||||
return self.rx_mcs
|
||||
end
|
||||
|
||||
function Neighbor:findRxRate()
|
||||
local r=(stations[self.mac:upper()].rx_rate)/1000
|
||||
self.rx_rate=adjust_rate(r,bandwidth)
|
||||
return self.rx_rate
|
||||
end
|
||||
|
||||
function Neighbor:log()
|
||||
local oktolog=true
|
||||
if self.lastseen ~= nil then
|
||||
if stations[self.mac:upper()].inactive >= INACTIVETIMEOUT then
|
||||
-- beacons expired
|
||||
self.signal="null"
|
||||
if nulledout[self.mac] == "true" then
|
||||
-- No need to double log inactive null's
|
||||
oktolog=false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.signal==0 then
|
||||
oktolog=false
|
||||
if nulledout[self.mac] == nil then
|
||||
-- First time we have seen this show up
|
||||
-- but it is at 0 wont be logged but will
|
||||
-- end up in snrcache
|
||||
nulledout[self.mac]="true"
|
||||
end
|
||||
end
|
||||
|
||||
if oktolog then
|
||||
nulledout[self.mac]="false"
|
||||
-- log neighbor data to datafile
|
||||
local f, err=assert(io.open(tmpdir.."/"..self.datafile, "a"),"Cannot open file ("..tmpdir.."/"..self.datafile..") for appending!")
|
||||
if f~=nil then
|
||||
local now=os.date("%m/%d/%Y %H:%M:%S",os.time())
|
||||
local outline=string.format("%s,%s,%s,%s,%s,%s,%s\n",now,self.signal,self.noise,self.tx_mcs,self.tx_rate,self.rx_mcs,self.rx_rate)
|
||||
f:write(outline)
|
||||
f:close()
|
||||
if self.signal == "null" then
|
||||
nulledout[self.mac]="true"
|
||||
end
|
||||
else
|
||||
print(err)
|
||||
end
|
||||
end
|
||||
return oktolog
|
||||
end
|
||||
-- Neighbor Class END
|
||||
|
||||
-- MAIN() -------------------------------------------------------------------------------------
|
||||
-- get wifi interface name
|
||||
wifiiface=get_ifname("wifi")
|
||||
|
||||
-- if Mesh RF is turned off do nothing
|
||||
if ( wifiiface == string.match(wifiiface,'eth.*')) then
|
||||
return
|
||||
end
|
||||
|
||||
-- check to make sure a prior instance is not still running
|
||||
local f = io.open(pidfile,"r")
|
||||
if (f) then
|
||||
local oldpid = f:read("*number")
|
||||
f:close()
|
||||
if (oldpid ~= nil and dir_exists("/proc/" .. oldpid)) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
--- create pid file to communicate I'm running
|
||||
f, err=assert(io.open(pidfile, "w"),"Cannot open file (pidfile) to write!")
|
||||
if (f) then
|
||||
local mypid = posix.unistd.getpid()
|
||||
f:write(mypid)
|
||||
f:close()
|
||||
end
|
||||
|
||||
--- Do not run if prior period rssi_monitor is still running
|
||||
local f = io.open(rssifile,"r")
|
||||
if (f) then
|
||||
local oldpid = f:read("*number")
|
||||
f:close()
|
||||
if (oldpid ~= nil and dir_exists("/proc/" .. oldpid)) then
|
||||
os.remove(pidfile)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- load the lasttime table
|
||||
if file_exists(lastdat) then
|
||||
local f,err=io.open(lastdat,"r")
|
||||
if f~=nil then
|
||||
for line in f:lines() do
|
||||
mac,last,nulled=string.match(line, "(.*)|(.*)|(.*)")
|
||||
lasttime[mac]=last
|
||||
nulledout[mac]=nulled
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
|
||||
-- get radio noise floor
|
||||
local nf=iwinfo["nl80211"].noise(wifiiface)
|
||||
if (nf < -101 or nf > -50) then
|
||||
nf=defnoise
|
||||
end
|
||||
|
||||
-- create tmp dir if needed
|
||||
if not dir_exists(tmpdir) then
|
||||
nxo.fs.mkdir(tmpdir)
|
||||
end
|
||||
|
||||
-- get system uptime
|
||||
--now=os.time()
|
||||
now=luci.sys.uptime()
|
||||
|
||||
-- get all stations
|
||||
stations=iwinfo["nl80211"].assoclist(wifiiface)
|
||||
|
||||
|
||||
-- load up arpcache
|
||||
arptable(
|
||||
function(a)
|
||||
arpcache[a["HW address"]:lower()]=a
|
||||
end
|
||||
)
|
||||
|
||||
-- get the current bandwidth setting
|
||||
local radio=aredn_info.getMeshRadioDevice()
|
||||
bandwidth=aredn_info.getChannelBW(radio)
|
||||
|
||||
-- iterate over all the stations
|
||||
for mstation in pairs(stations) do
|
||||
local n=Neighbor.create(mstation)
|
||||
table.insert(neighbors,n)
|
||||
end
|
||||
|
||||
-- get all the existing files in tmpdir
|
||||
local tmpdirlist={}
|
||||
for maclist in nxo.fs.dir(tmpdir) do
|
||||
maclistbase=nxo.fs.basename(maclist)
|
||||
table.insert(tmpdirlist,maclistbase)
|
||||
end
|
||||
|
||||
-- neighbors loop START
|
||||
for _,n in pairs(neighbors) do
|
||||
-- trim datafile
|
||||
file_trim(tmpdir.."/"..n.datafile,MAXLINES)
|
||||
if n:log()==true then
|
||||
lasttime[n.mac]=now
|
||||
end
|
||||
end
|
||||
-- neighbors loop END
|
||||
|
||||
-- update snr.dat
|
||||
local snrdatcache={}
|
||||
if not file_exists(lastdat) then
|
||||
-- create file
|
||||
local f,err=assert(io.open(lastdat,"w+"),"Cannot create "..lastdat)
|
||||
f:close()
|
||||
end
|
||||
for line in io.lines(lastdat) do
|
||||
local mac,lastt,nulledoutprev=string.match(line,"(.*)|(.*)|(.*)")
|
||||
if ((now-lastt) < AGETIME) then
|
||||
-- keep it
|
||||
snrdatcache[mac]=lastt
|
||||
|
||||
-- check if in neighbors table
|
||||
local foundneighbor=false
|
||||
for _,n in pairs(neighbors) do
|
||||
if n.mac == mac then
|
||||
foundneighbor=true
|
||||
end
|
||||
end
|
||||
|
||||
-- If wasn't previously nulled out and we don't have it in the neigbors table write a null
|
||||
if nulledoutprev[mac] == "false" and foundneigbor == false then
|
||||
|
||||
-- find the log file name
|
||||
for maclist in nxo.fs.glob(tmpdir.."/"..mac.."*") do
|
||||
logdatafile=macclist
|
||||
end
|
||||
|
||||
-- Write a null to the log file
|
||||
local f, err=assert(io.open(logdatafile, "a"),"Cannot open file ("..logdatafile..") for appending!")
|
||||
if f~=nil then
|
||||
local now=os.date("%m/%d %H:%M:%S",os.time())
|
||||
local outline=string.format("%s,%s,%s,%s,%s,%s,%s\n",now,'null',nf,'0','0','0','0')
|
||||
f:write(outline)
|
||||
f:close()
|
||||
nulledout[mac]="true"
|
||||
else
|
||||
-- Don't log the null into SNRLog cause we were not successful
|
||||
-- Though the assert() above should cause this too.
|
||||
nulledout[mac]="false"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
-- find the file and purge it
|
||||
for maclist in nxo.fs.glob(tmpdir.."/"..mac.."*") do
|
||||
nxo.fs.remove(maclist)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _,n in pairs(neighbors) do
|
||||
snrdatcache[n.mac]=now
|
||||
end
|
||||
|
||||
-- re-write snr.dat file
|
||||
local f,err=assert(io.open(lastdat,"w+"),"Cannot overwrite "..lastdat)
|
||||
for k,v in pairs(snrdatcache) do
|
||||
f:write(string.format("%s|%s|%s\n",k,v,nulledout[k]))
|
||||
end
|
||||
f:close()
|
||||
|
||||
os.remove(pidfile)
|
||||
|
||||
-- END MAIN
|
Loading…
Reference in New Issue