-#!/usr/bin/env lua
+#!/usr/bin/lua
+
+function getConfig(configname)
+
+ local uci=require("uci")
+ local cur=uci.cursor()
+ local config
+ if configname then
+ config=configname
+ else
+ config="beacon"
+ end
+
+ logging = cur.get(config,"logging","enabled")
+
+ mqtt_host = cur.get(config,"mqtt","host")
+ mqtt_port = cur.get(config,"mqtt","port")
+ mqtt_id = cur.get(config,"mqtt","id")
+ mqtt_topic = cur.get(config,"mqtt","topic")
+
+ mqtt_user = cur.get(config,"mqtt","user")
+ mqtt_passwd = cur.get(config,"mqtt","password")
+
+ if mqtt_host and not mqtt_id then
+ socket = require("socket")
+ posix = require("posix")
+ hostname = socket.dns.gethostname()
+ pid = posix.getpid()
+ mqtt_id="beaconmon-"..hostname.."-"..pid
+ end
+
+ if mqtt_host and not mqtt_port then
+ mqtt_port = 1883
+ end
+
+ if mqtt_host and not mqtt_topic then
+ mqtt_topic = 'beaconmon/{type}/{details}'
+ end
+
+end
+
+function capture(cmd, raw)
+ local f = assert(io.popen(cmd, 'r'))
+ local s = assert(f:read('*a'))
+ f:close()
+ if raw then return s end
+ s = string.gsub(s, '^%s+', '')
+ s = string.gsub(s, '%s+$', '')
+ s = string.gsub(s, '[\n\r]+', ' ')
+ return s
+end
+
+function mqtt_encode(str)
+ if (str) then
+ str = string.gsub (str, "\n", "")
+ str = string.gsub (str, "/", "-")
+ end
+ return str
+end
+
+function printLog(str)
+ if logging=="on" then
+ capture("logger -t beaconmon "..str)
+ else
+ print(str)
+ end
+end
function run_command(cmd)
function open_dump()
- f = assert(io.popen ("hcidump --raw"))
- run_command("kill `pgrep hcitool`")
- run_command("hciconfig hci0 down")
- run_command("hciconfig hci0 up")
- f_null = assert(io.popen ("hcitool lescan --duplicates"))
+ run_command("/bin/kill `/usr/bin/pgrep hcidump`")
+ run_command("/bin/kill `/usr/bin/pgrep hcitool`")
+ f = assert(io.popen ("/usr/bin/hcidump --raw"))
+ run_command("/usr/bin/hciconfig hci0 down")
+ run_command("/usr/bin/hciconfig hci0 up")
+ f_null = assert(io.popen ("/usr/bin/hcitool lescan --duplicates --passive"))
return f
local s = '{ '
for k,v in pairs(o) do
if type(k) ~= 'number' then k = '"'..k..'"' end
--- s = s .. '['..k..'] = ' .. dump(v) .. ','
- s = s .. dump(v) .. ','
+ s = s .. '['..k..'] = ' .. dump(v) .. ','
+-- s = s .. dump(v) .. ','
end
return s .. '} '
else
return (s:gsub("^%s*(.-)%s*$", "%1"))
end
+function mqtt_pub(path,value)
+ res=mqtt_client:publish(path,value)
+ printLog("Pub "..path.." "..value.." returned "..res);
+ return res
+end
+
function process_packet(packet)
- bytes={}
- idx=1
+ local bytes={}
+ local idx=1
+ local len
+ local mac
+ local flags
+ local power
+ local tx
+ local type
+ local paysublen
+ local uuid
+ local major
+ local minor
+ local details
if packet:len()>1 then
type=""
mac=bytes[13]..':'..bytes[12]..':'..bytes[11]..':'..bytes[10]..':'..bytes[9]..':'..bytes[8]
flags=bytes[14]
- power=tonumber("0x"..bytes[len-1])-256
+ local j = 15
tx=tonumber("0x"..bytes[len])-256
- j = 15
while j<len-2 do
paysublen=tonumber('0x'..bytes[j])
- if bytes[j+1]=="FF" and bytes[j+2]=="4C" and bytes[j+3]=="00" and bytes[j+4]=="02" and bytes[j+5]=="15" then
+ if bytes[j+1]=="09" then
+ -- Standard name beacon
+ type="name"
+ name=""
+ for i=j+2,j+paysublen do
+ name=name..string.char(tonumber('0x'..bytes[i]))
+ end
+ printLog("name="..name)
+ elseif bytes[j+1]=="FF" and bytes[j+2]=="4C" and bytes[j+3]=="00" and bytes[j+4]=="02" and bytes[j+5]=="15" then
-- Standard UUID iBeacon
type="ibeacon"
- uuid1=bytes[j+6]..bytes[j+7]..bytes[j+8]..bytes[j+9]
- uuid2=bytes[j+10]..bytes[j+11]
- uuid3=bytes[j+12]..bytes[j+13]
- uuid4=bytes[j+14]..bytes[j+15]
- uuid5=bytes[j+16]..bytes[j+17]..bytes[j+18]..bytes[j+19]..bytes[j+20]..bytes[j+21]
+ local uuid1=bytes[j+6]..bytes[j+7]..bytes[j+8]..bytes[j+9]
+ local uuid2=bytes[j+10]..bytes[j+11]
+ local uuid3=bytes[j+12]..bytes[j+13]
+ local uuid4=bytes[j+14]..bytes[j+15]
+ local uuid5=bytes[j+16]..bytes[j+17]..bytes[j+18]..bytes[j+19]..bytes[j+20]..bytes[j+21]
uuid=string.lower(uuid1..'-'..uuid2..'-'..uuid3..'-'..uuid4..'-'..uuid5)
major=bytes[j+23]..bytes[j+22]
minor=bytes[j+25]..bytes[j+24]
+ power=tonumber("0x"..bytes[len-1])-256
end
j=j+1+paysublen
end
if type=="ibeacon" then
- print(string.format("{type:'ibeacon',mac:'%s',uuid:'%s',major:'%s',minor:'%s',power:%d,tx:%d}",mac,uuid,major,minor,power,tx))
+ printLog(string.format("{type:'ibeacon',mac:'%s',uuid:'%s',major:'%s',minor:'%s',power:%d,tx:%d}",mac,uuid,major,minor,power,tx))
+ details=uuid..'/'..major..'/'..minor
+ elseif type=="name" then
+ printLog(string.format("{type:'ble',mac:'%s',name:'%s'}",mac,name))
+ details=name
else
- print(dump(bytes))
+ type='unknown'
+ details=dump(bytes)
+ printLog(details)
end
+ if not (type=="unknown") then
+ mqtt_path=string.gsub(mqtt_topic,"{(.-)}",
+ function (name)
+ if name=="type" then
+ return mqtt_encode(type)
+ elseif name=="details" then
+ return mqtt_encode(details)
+ else
+ return '{'..name..'}'
+ end
+ end)
+
+ if not pcall(mqtt_pub,mqtt_path,tx) then
+ printLog('Reconnecting MQTT...')
+ mqtt_client:connect(mqtt_id)
+ end
+
+ end
end
end
for line in inp:lines() do
+ printLog('Received ' .. line);
+
lchr=line:sub(1,1)
line=trim(line)
end
+getConfig(arg[1])
+
+if mqtt_host then
+ MQTT = require "mosquitto"
+ mqtt_client = MQTT.new(mqtt_id)
+ if mqtt_user then
+ mqtt_client:login_set(mqtt_user, mqtt_passwd)
+ end
+ mqtt_client:connect(mqtt_host,mqtt_port)
+end
+
inp = open_dump()
read_loop()