lua-geolocate: add package for WLAN-based geolocation based on openwifi.su
Based-on-patch-by: Jan-Tarek Butt <tarek@ring0.de>
This commit is contained in:
parent
5c6476ea58
commit
53a659abf8
|
@ -0,0 +1,23 @@
|
||||||
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
|
PKG_NAME:=lua-geolocate
|
||||||
|
PKG_VERSION:=1
|
||||||
|
|
||||||
|
include $(INCLUDE_DIR)/package.mk
|
||||||
|
|
||||||
|
define Package/lua-geolocate
|
||||||
|
SECTION:=libs
|
||||||
|
CATEGORY:=Libraries
|
||||||
|
TITLE:=WLAN-based geolocation librari based on openwifi.su
|
||||||
|
DEPENDS:=+libubus-lua +libiwinfo-lua +lua-jsonc
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Build/Compile
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/lua-geolocate/install
|
||||||
|
$(INSTALL_DIR) $(1)/usr/lib/lua
|
||||||
|
$(INSTALL_DATA) src/geolocate.lua $(1)/usr/lib/lua/
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(eval $(call BuildPackage,lua-geolocate))
|
|
@ -0,0 +1,87 @@
|
||||||
|
local iwinfo = require 'iwinfo'
|
||||||
|
local json = require 'jsonc'
|
||||||
|
local ubus = require 'ubus'
|
||||||
|
|
||||||
|
|
||||||
|
local function canon_bssid(bssid)
|
||||||
|
return bssid:upper():gsub(':', '')
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Iterates over all active WLAN interfaces
|
||||||
|
-- Returning true from the callback function will skip all remaining
|
||||||
|
-- interfaces of the same radio
|
||||||
|
local function foreach_radio(f)
|
||||||
|
local uconn = assert(ubus.connect(), 'failed to connect to ubus')
|
||||||
|
local status = uconn:call('network.wireless', 'status', {})
|
||||||
|
ubus.close(uconn)
|
||||||
|
|
||||||
|
for name, radio in pairs(status) do
|
||||||
|
for _, iface in ipairs(radio.interfaces) do
|
||||||
|
if f(iface.ifname) then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function receive_json(request)
|
||||||
|
local f = assert(io.popen(string.format("exec wget -T 15 -q -O- '%s'", request)), 'failed to run wget')
|
||||||
|
local data = f:read('*a')
|
||||||
|
f:close()
|
||||||
|
|
||||||
|
return json.parse(data)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function locate(blacklist)
|
||||||
|
local done_bssids = {}
|
||||||
|
for _, bssid in ipairs(blacklist or {}) do
|
||||||
|
done_bssids[canon_bssid(bssid)] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local found_bssids = {}
|
||||||
|
|
||||||
|
foreach_radio(function(ifname)
|
||||||
|
local iw = iwinfo[iwinfo.type(ifname)]
|
||||||
|
if not iw then
|
||||||
|
-- Skip other ifaces of this radio, as they
|
||||||
|
-- will have the same type
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local scanlist = iw.scanlist(ifname)
|
||||||
|
if not scanlist then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, entry in ipairs(scanlist) do
|
||||||
|
local bssid = canon_bssid(entry.bssid)
|
||||||
|
if not done_bssids[bssid] then
|
||||||
|
table.insert(found_bssids, bssid)
|
||||||
|
done_bssids[bssid] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert(#found_bssids >= 12, 'insufficient BSSIDs found')
|
||||||
|
|
||||||
|
local data = receive_json('http://openwifi.su/api/v1/bssids/' .. table.concat(found_bssids, ','))
|
||||||
|
assert(type(data) == 'table' and data.lon and data.lat, 'location not available')
|
||||||
|
|
||||||
|
return data
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local geolocate = {}
|
||||||
|
|
||||||
|
function geolocate.locate(blacklist)
|
||||||
|
ok, result = pcall(locate, blacklist)
|
||||||
|
if ok then
|
||||||
|
return result
|
||||||
|
else
|
||||||
|
return nil, result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return geolocate
|
Loading…
Reference in New Issue