X-Git-Url: https://git.rvb.name/openhab-process.git/blobdiff_plain/daa57f38fb9540a14593936b6886d47800abce9c..229358bcd45588510fe83e5d88142725b7218802:/mqtt-bt/scan-beacons diff --git a/mqtt-bt/scan-beacons b/mqtt-bt/scan-beacons index b73d674..d6d0d26 100644 --- a/mqtt-bt/scan-beacons +++ b/mqtt-bt/scan-beacons @@ -1,28 +1,67 @@ #!/usr/bin/lua +json = require("json") +socket = require("socket") + function getConfig(configname) - local uci=require("uci") - local cur=uci.cursor() + local status,uci = pcall(require,"uci") + local config - if configname then - config=configname - else - config="beacon" - end - logging = cur.get(config,"logging","enabled") + if status then + + if configname then + config=configname + else + config="beacon" + end + + local cur=uci.cursor() + + 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_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") - mqtt_user = cur.get(config,"mqtt","user") - mqtt_passwd = cur.get(config,"mqtt","password") + else + + local status,ini = pcall(require,"ini") + if not status then + os.exit(1) + end + + if configname then + config=configname + else + config="/etc/beacon.ini" + end + local cur=ini.parse_file(config) + + logging = cur["logging"]["enabled"] + + mqtt_host = cur["mqtt"]["host"] + mqtt_port = cur["mqtt"]["port"] + mqtt_id = cur["mqtt"]["id"] + mqtt_topic = cur["mqtt"]["topic"] + + mqtt_user = cur["mqtt"]["user"] + mqtt_passwd = cur["mqtt"]["password"] + + end + + hostname = socket.dns.gethostname() if mqtt_host and not mqtt_id then - mqtt_id="beaconmon" + socket = require("socket") + posix = require("posix") + pid = posix.getpid() + mqtt_id="beaconmon-"..hostname.."-"..pid end if mqtt_host and not mqtt_port then @@ -57,9 +96,12 @@ function mqtt_encode(str) end function printLog(str) - if logging=="on" then - capture("logger -t beaconmon "..str) - else + if logging=="yes" then + capture("logger -t beaconmon \""..str.."\"") + print(str) + elseif logging=="syslog" then + capture("logger -t beaconmon \""..str.."\"") + elseif logging=="stdout" then print(str) end end @@ -74,161 +116,156 @@ end function open_dump() - 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")) + f = assert(io.popen ("/usr/bin/btmon")) + run_command("hciconfig hci0 down") + run_command("hciconfig hci0 up") + f_null = assert(io.popen ("hcitool lescan --duplicates")) return f 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) return (s:gsub("^%s*(.-)%s*$", "%1")) end +local function starts_with(str, start) + return str:sub(1, #start) == start +end + function mqtt_pub(path,value) - printLog("Pub "..path.." "..value) - return mqtt_client:publish(path,value) + res=mqtt_client:publish(path,value) + printLog("Pub "..path.." returned "..res); + return res end 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 + + packet['origin'] = hostname + + mac = packet['Address'] + uuid = packet['UUID'] + type = packet['Type'] + name = packet['Name (complete)'] + + if type and starts_with(type,'iBeacon') then + details=uuid + elseif name then + if not(type) then + type="name" + end + details=name + else + if not type then + type='unknown' + end + 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] - power=tonumber("0x"..bytes[len-1])-256 - tx=tonumber("0x"..bytes[len])-256 - local 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 - -- 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] - 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 - 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() - - packet = "" - - for line in inp:lines() do - - lchr=line:sub(1,1) - line=trim(line) - - if lchr=="<" or lchr==">" then - line = trim(line:sub(2)) - end +function starts(String,Start) + return string.sub(String,1,string.len(Start))==Start +end - if not (lchr == " ") then - process_packet(packet) - packet = "" - 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 - llen=line:len() +function read_loop() - if llen<59 then - packet = packet .. " " .. line - process_packet(packet) - packet="" - else - packet = packet .. " " .. line - end + packet={} + inbound=false + + while true do + + str=inp:read("*l") + + if str then + + str=trim(str) + + 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 + elseif #t==1 and name then + if not(packet[name..'.list']) then + packet[name..'.list']={} + end + table.insert(packet[name..'.list'],(trim(t[1]))) + end + end + + if starts(str,'> HCI Event: LE Meta Event (0x3e)') then + inbound=true + name=nil + 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 - MQTT = require "paho.mqtt" - mqtt_client = MQTT.client.create(mqtt_host, mqtt_port) + MQTT = require "mosquitto" + mqtt_client = MQTT.new(mqtt_id) if mqtt_user then - mqtt_client:auth(mqtt_user, mqtt_passwd) + mqtt_client:login_set(mqtt_user, mqtt_passwd) end - mqtt_client:connect(mqtt_id) + mqtt_client:connect(mqtt_host,mqtt_port) end inp = open_dump()