3 function getConfig(configname)
5 local uci=require("uci")
14 logging = cur.get(config,"logging","enabled")
16 mqtt_host = cur.get(config,"mqtt","host")
17 mqtt_port = cur.get(config,"mqtt","port")
18 mqtt_id = cur.get(config,"mqtt","id")
19 mqtt_topic = cur.get(config,"mqtt","topic")
21 mqtt_user = cur.get(config,"mqtt","user")
22 mqtt_passwd = cur.get(config,"mqtt","password")
24 if mqtt_host and not mqtt_id then
25 socket = require("socket")
26 posix = require("posix")
27 hostname = socket.dns.gethostname()
29 mqtt_id="beaconmon-"..hostname.."-"..pid
32 if mqtt_host and not mqtt_port then
36 if mqtt_host and not mqtt_topic then
37 mqtt_topic = 'beaconmon/{type}/{details}'
42 function capture(cmd, raw)
43 local f = assert(io.popen(cmd, 'r'))
44 local s = assert(f:read('*a'))
46 if raw then return s end
47 s = string.gsub(s, '^%s+', '')
48 s = string.gsub(s, '%s+$', '')
49 s = string.gsub(s, '[\n\r]+', ' ')
53 function mqtt_encode(str)
55 str = string.gsub (str, "\n", "")
56 str = string.gsub (str, "/", "-")
61 function printLog(str)
63 capture("logger -t beaconmon "..str)
69 function run_command(cmd)
71 local file = assert(io.popen(cmd, 'r'))
72 local output = file:read('*all')
79 run_command("/bin/kill `/usr/bin/pgrep hcidump`")
80 run_command("/bin/kill `/usr/bin/pgrep hcitool`")
81 f = assert(io.popen ("/usr/bin/hcidump --raw"))
82 run_command("/usr/bin/hciconfig hci0 down")
83 run_command("/usr/bin/hciconfig hci0 up")
84 f_null = assert(io.popen ("/usr/bin/hcitool lescan --duplicates --passive"))
91 if type(o) == 'table' then
93 for k,v in pairs(o) do
94 if type(k) ~= 'number' then k = '"'..k..'"' end
95 s = s .. '['..k..'] = ' .. dump(v) .. ','
96 -- s = s .. dump(v) .. ','
105 return (s:gsub("^%s*(.-)%s*$", "%1"))
108 function mqtt_pub(path,value)
109 res=mqtt_client:publish(path,value)
110 printLog("Pub "..path.." "..value.." returned "..res);
114 function process_packet(packet)
130 if packet:len()>1 then
132 while packet:len()>2 do
133 bytes[idx]=trim(packet:sub(1,3))
139 if bytes[1]=='04' and bytes[2]=='3E' then
142 mac=bytes[13]..':'..bytes[12]..':'..bytes[11]..':'..bytes[10]..':'..bytes[9]..':'..bytes[8]
145 tx=tonumber("0x"..bytes[len])-256
147 paysublen=tonumber('0x'..bytes[j])
148 if bytes[j+1]=="09" then
149 -- Standard name beacon
152 for i=j+2,j+paysublen do
153 name=name..string.char(tonumber('0x'..bytes[i]))
155 printLog("name="..name)
156 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
157 -- Standard UUID iBeacon
159 local uuid1=bytes[j+6]..bytes[j+7]..bytes[j+8]..bytes[j+9]
160 local uuid2=bytes[j+10]..bytes[j+11]
161 local uuid3=bytes[j+12]..bytes[j+13]
162 local uuid4=bytes[j+14]..bytes[j+15]
163 local uuid5=bytes[j+16]..bytes[j+17]..bytes[j+18]..bytes[j+19]..bytes[j+20]..bytes[j+21]
164 uuid=string.lower(uuid1..'-'..uuid2..'-'..uuid3..'-'..uuid4..'-'..uuid5)
165 major=bytes[j+23]..bytes[j+22]
166 minor=bytes[j+25]..bytes[j+24]
167 power=tonumber("0x"..bytes[len-1])-256
171 if type=="ibeacon" then
172 printLog(string.format("{type:'ibeacon',mac:'%s',uuid:'%s',major:'%s',minor:'%s',power:%d,tx:%d}",mac,uuid,major,minor,power,tx))
173 details=uuid..'/'..major..'/'..minor
174 elseif type=="name" then
175 printLog(string.format("{type:'ble',mac:'%s',name:'%s'}",mac,name))
182 if not (type=="unknown") then
183 mqtt_path=string.gsub(mqtt_topic,"{(.-)}",
186 return mqtt_encode(type)
187 elseif name=="details" then
188 return mqtt_encode(details)
190 return '{'..name..'}'
194 if not pcall(mqtt_pub,mqtt_path,tx) then
195 printLog('Reconnecting MQTT...')
196 mqtt_client:connect(mqtt_id)
209 for line in inp:lines() do
211 printLog('Received ' .. line);
216 if lchr=="<" or lchr==">" then
217 line = trim(line:sub(2))
220 if not (lchr == " ") then
221 process_packet(packet)
228 packet = packet .. " " .. line
229 process_packet(packet)
232 packet = packet .. " " .. line
242 MQTT = require "mosquitto"
243 mqtt_client = MQTT.new(mqtt_id)
245 mqtt_client:login_set(mqtt_user, mqtt_passwd)
247 mqtt_client:connect(mqtt_host,mqtt_port)