#!/usr/bin/lua
+json = require("json")
+
function getConfig(configname)
local uci=require("uci")
end
function printLog(str)
- if logging=="on" then
+ if logging=="yes" then
capture("logger -t beaconmon "..str)
else
print(str)
function open_dump()
- run_command("/bin/kill `/usr/bin/pgrep hcidump`")
+ run_command("/bin/kill `/usr/bin/pgrep btmon`")
run_command("/bin/kill `/usr/bin/pgrep hcitool`")
- f = assert(io.popen ("/usr/bin/hcidump --raw"))
+ f = assert(io.popen ("/usr/bin/stdbuf -o0 /usr/bin/btmon"))
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"))
end
function dump(o)
- if type(o) == 'table' then
- 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) .. ','
- end
- return s .. '} '
- else
- return tostring(o)
- end
+ return json.encode(o)
end
function trim(s)
function process_packet(packet)
- 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
+ local type
+ local name
+
+ mac = packet['Address']
+ uuid = packet['uuid']
+ type = packet['Type']
+ name = packet['Name (complete)']
+
+ if type=='iBeacon' then
+ details=uuid
+ elseif name then
+ type="name"
+ details=name
+ else
+ type='unknown'
+ details=mac
+ end
- if packet:len()>1 then
-
- while packet:len()>2 do
- bytes[idx]=trim(packet:sub(1,3))
- idx=idx+1
- packet=packet:sub(4)
- end
- len = idx-1
-
- if bytes[1]=='04' and bytes[2]=='3E' then
- -- BLE Beacon?
- type=""
- mac=bytes[13]..':'..bytes[12]..':'..bytes[11]..':'..bytes[10]..':'..bytes[9]..':'..bytes[8]
- flags=bytes[14]
- local j = 15
- tx=tonumber("0x"..bytes[len])-256
- while j<len-2 do
- paysublen=tonumber('0x'..bytes[j])
- 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"
- 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
- 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
- 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 (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
+ if not pcall(mqtt_pub,mqtt_path,dump(packet)) then
+ printLog('Reconnecting MQTT...')
+ mqtt_client:connect(mqtt_id)
end
+
end
end
-function read_loop()
+function starts(String,Start)
+ return string.sub(String,1,string.len(Start))==Start
+end
+
+function split(inputstr, sep)
+ if sep == nil then
+ sep = "%s"
+ end
+ local t={} ; i=1
+ for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
+ t[i] = str
+ i = i + 1
+ end
+ return t
+end
- packet = ""
+function read_loop()
- for line in inp:lines() do
+ packet={}
+ inbound=false
- printLog('Received ' .. line);
+ while true do
- lchr=line:sub(1,1)
- line=trim(line)
+ str=inp:read("*l")
- if lchr=="<" or lchr==">" then
- line = trim(line:sub(2))
- end
+ if str then
- if not (lchr == " ") then
- process_packet(packet)
- packet = ""
- end
+ str=trim(str)
- llen=line:len()
+ if inbound then
+ t = split(str,':')
+ if #t>=2 then
+ name=t[1]
+ value=trim(table.concat(t,':',2))
+ if name=="Address" then
+ value=split(value)[1]
+ end
+ packet[name]=value
+ end
+ end
- if llen<59 then
- packet = packet .. " " .. line
- process_packet(packet)
- packet=""
- else
- packet = packet .. " " .. line
- end
+ if starts(str,'> HCI Event: LE Meta Event (0x3e)') then
+ inbound=true
+ elseif starts(str,'RSSI:') then
+ inbound=false
+ process_packet(packet)
+ packet={}
+ end
+
+ end
end
end
+io.stdout:setvbuf('no')
+io.stdin:setvbuf('no')
+
getConfig(arg[1])
if mqtt_host then