4 socket = require("socket")
6 function getConfig(configname)
8 local status,uci = pcall(require,"uci")
20 local cur=uci.cursor()
22 logging = cur.get(config,"logging","enabled")
24 mqtt_host = cur.get(config,"mqtt","host")
25 mqtt_port = cur.get(config,"mqtt","port")
26 mqtt_id = cur.get(config,"mqtt","id")
27 mqtt_topic = cur.get(config,"mqtt","topic")
29 mqtt_user = cur.get(config,"mqtt","user")
30 mqtt_passwd = cur.get(config,"mqtt","password")
34 local status,ini = pcall(require,"ini")
42 config="/etc/beacon.ini"
45 local cur=ini.parse_file(config)
47 logging = cur["logging"]["enabled"]
49 mqtt_host = cur["mqtt"]["host"]
50 mqtt_port = cur["mqtt"]["port"]
51 mqtt_id = cur["mqtt"]["id"]
52 mqtt_topic = cur["mqtt"]["topic"]
54 mqtt_user = cur["mqtt"]["user"]
55 mqtt_passwd = cur["mqtt"]["password"]
59 hostname = socket.dns.gethostname()
60 if mqtt_host and not mqtt_id then
61 socket = require("socket")
62 posix = require("posix")
64 mqtt_id="beaconmon-"..hostname.."-"..pid
67 if mqtt_host and not mqtt_port then
71 if mqtt_host and not mqtt_topic then
72 mqtt_topic = 'beaconmon/{type}/{details}'
77 function capture(cmd, raw)
78 local f = assert(io.popen(cmd, 'r'))
79 local s = assert(f:read('*a'))
81 if raw then return s end
82 s = string.gsub(s, '^%s+', '')
83 s = string.gsub(s, '%s+$', '')
84 s = string.gsub(s, '[\n\r]+', ' ')
88 function mqtt_encode(str)
90 str = string.gsub (str, "\n", "")
91 str = string.gsub (str, ":", "-")
92 str = string.gsub (str, "/", "-")
93 str = string.gsub (str, " ", "_")
98 function printLog(str)
99 if logging=="yes" then
100 capture("logger -t beaconmon \""..str.."\"")
102 elseif logging=="syslog" then
103 capture("logger -t beaconmon \""..str.."\"")
104 elseif logging=="stdout" then
109 function run_command(cmd)
111 local file = assert(io.popen(cmd, 'r'))
112 local output = file:read('*all')
119 run_command("/usr/bin/pkill btmon")
120 run_command("/usr/bin/pkill hcitool")
121 f = assert(io.popen ("/usr/bin/stdbuf -o0 /usr/bin/btmon"))
122 run_command("hciconfig hci0 down")
123 run_command("hciconfig hci0 up")
124 f_null = assert(io.popen ("hcitool lescan --duplicates --passive"))
131 return json.encode(o)
135 return (s:gsub("^%s*(.-)%s*$", "%1"))
138 local function starts_with(str, start)
139 return str:sub(1, #start) == start
142 function mqtt_pub(path,value)
143 res=mqtt_client:publish(path,value)
144 printLog("Pub "..path.." returned "..res);
148 function process_packet(packet)
156 packet['origin'] = hostname
158 mac = packet['Address']
159 uuid = packet['UUID']
160 type = packet['Type']
161 name = packet['Name (complete)']
163 if type and starts_with(type,'iBeacon') then
177 if not (type=="unknown") then
178 mqtt_path=string.gsub(mqtt_topic,"{(.-)}",
181 return mqtt_encode(type)
182 elseif name=="details" then
183 return mqtt_encode(details)
185 return '{'..name..'}'
189 if not pcall(mqtt_pub,mqtt_path,dump(packet)) then
190 printLog('Reconnecting MQTT...')
191 mqtt_client:connect(mqtt_id)
198 function starts(String,Start)
199 return string.sub(String,1,string.len(Start))==Start
202 function split(inputstr, sep)
207 for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
231 value=trim(table.concat(t,':',2))
232 if name=="Address" then
233 value=split(value)[1]
236 elseif #t==1 and name then
237 if not(packet[name..'.list']) then
238 packet[name..'.list']={}
240 table.insert(packet[name..'.list'],(trim(t[1])))
244 if starts(str,'> HCI Event: LE Meta Event (0x3e)') then
247 elseif starts(str,'RSSI:') then
249 process_packet(packet)
259 io.stdout:setvbuf('no')
260 io.stdin:setvbuf('no')
265 MQTT = require "mosquitto"
266 mqtt_client = MQTT.new(mqtt_id)
268 mqtt_client:login_set(mqtt_user, mqtt_passwd)
270 mqtt_client:connect(mqtt_host,mqtt_port)