BLE beacon scan added (initial commit, still too many TODOs)
[openhab-process.git] / mqtt-bt / scan-beacons
1 #!/usr/bin/env lua
2
3 function run_command(cmd)
4
5   local file = assert(io.popen(cmd, 'r'))
6   local output = file:read('*all')
7   file:close()
8
9 end
10
11 function open_dump()
12
13   f = assert(io.popen ("hcidump --raw"))
14   run_command("kill `pgrep hcitool`")
15   run_command("hciconfig hci0 down")
16   run_command("hciconfig hci0 up")
17   f_null = assert(io.popen ("hcitool lescan --duplicates"))
18
19   return f
20
21 end
22
23 function dump(o)
24    if type(o) == 'table' then
25       local s = '{ '
26       for k,v in pairs(o) do
27          if type(k) ~= 'number' then k = '"'..k..'"' end
28 --         s = s .. '['..k..'] = ' .. dump(v) .. ','
29          s = s .. dump(v) .. ','
30       end
31       return s .. '} '
32    else
33       return tostring(o)
34    end
35 end
36
37 function trim(s)
38   return (s:gsub("^%s*(.-)%s*$", "%1"))
39 end
40
41 function process_packet(packet)
42
43   bytes={}
44   idx=1
45
46   if packet:len()>1 then
47
48     while packet:len()>2 do
49       bytes[idx]=trim(packet:sub(1,3))
50       idx=idx+1
51       packet=packet:sub(4)
52     end
53     len = idx-1
54
55     if bytes[1]=='04' and bytes[2]=='3E' then
56       -- BLE Beacon?
57       type=""
58       mac=bytes[13]..':'..bytes[12]..':'..bytes[11]..':'..bytes[10]..':'..bytes[9]..':'..bytes[8]
59       flags=bytes[14]
60       power=tonumber("0x"..bytes[len-1])-256
61       tx=tonumber("0x"..bytes[len])-256
62       j = 15
63       while j<len-2 do
64         paysublen=tonumber('0x'..bytes[j])
65         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
66           -- Standard UUID iBeacon
67           type="ibeacon"
68           uuid1=bytes[j+6]..bytes[j+7]..bytes[j+8]..bytes[j+9]
69           uuid2=bytes[j+10]..bytes[j+11]
70           uuid3=bytes[j+12]..bytes[j+13]
71           uuid4=bytes[j+14]..bytes[j+15]
72           uuid5=bytes[j+16]..bytes[j+17]..bytes[j+18]..bytes[j+19]..bytes[j+20]..bytes[j+21]
73           uuid=string.lower(uuid1..'-'..uuid2..'-'..uuid3..'-'..uuid4..'-'..uuid5)
74           major=bytes[j+23]..bytes[j+22]
75           minor=bytes[j+25]..bytes[j+24]
76         end
77         j=j+1+paysublen
78       end
79       if type=="ibeacon" then
80         print(string.format("{type:'ibeacon',mac:'%s',uuid:'%s',major:'%s',minor:'%s',power:%d,tx:%d}",mac,uuid,major,minor,power,tx))
81       else
82         print(dump(bytes))
83       end
84     end
85   end
86
87 end
88
89 function read_loop()
90
91   packet = ""
92
93   for line in inp:lines() do
94
95     lchr=line:sub(1,1)
96     line=trim(line)
97
98     if lchr=="<" or lchr==">" then
99       line = trim(line:sub(2))
100     end
101
102     if not (lchr == " ") then
103       process_packet(packet)
104       packet = ""
105     end
106
107     llen=line:len()
108
109     if llen<59 then
110       packet = packet .. " " .. line
111       process_packet(packet)
112       packet=""
113     else
114       packet = packet .. " " .. line
115     end    
116     
117   end
118
119 end
120
121 inp = open_dump()
122
123 read_loop()