]> www.average.org Git - loctrkd.git/commitdiff
Add googlemaps lookaside backend
authorEugene Crosser <crosser@average.org>
Thu, 26 May 2022 17:24:59 +0000 (19:24 +0200)
committerEugene Crosser <crosser@average.org>
Thu, 26 May 2022 17:24:59 +0000 (19:24 +0200)
debian/gps303.conf
gps303/googlemaps.py [new file with mode: 0644]
gps303/lookaside.py
gps303/mkgpx.py
gps303/opencellid.py

index f19b4af8e3adad3f21f6d757a639aebb3f4ba5de..9d5ed3ca161c977f4018153d85765309cf502303 100644 (file)
@@ -13,7 +13,9 @@ htmlfile = /var/lib/gps303/index.html
 dbfn = /var/lib/gps303/gps303.sqlite
 
 [lookaside]
-# "opencellid" is the only implemented backend for the time being
+# "opencellid" and "googlemaps" can be here. Both require an access token,
+# though googlemaps is only online, while opencellid backend looks up a
+# local database, that can be updated once a week or once a month.
 backend = opencellid
 
 [opencellid]
diff --git a/gps303/googlemaps.py b/gps303/googlemaps.py
new file mode 100644 (file)
index 0000000..bb19a64
--- /dev/null
@@ -0,0 +1,65 @@
+import googlemaps as gmaps
+from sqlite3 import connect
+
+gclient = None
+
+
+def init(conf):
+    global gclient
+    with open(conf["googlemaps"]["accesstoken"], encoding="ascii") as fl:
+        token = fl.read().rstrip()
+    gclient = gmaps.Client(key=token)
+
+
+def lookup(mcc, mnc, gsm_cells, wifi_aps):
+    kwargs = {
+        "home_mobile_country_code": mcc,
+        "home_mobile_network_code": mnc,
+        "radio_type": "gsm",
+        "carrier": "O2",
+        "consider_ip": False,
+        "cell_towers": [
+            {
+                "locationAreaCode": loc,
+                "cellId": cellid,
+                "signalStrength": sig,
+            }
+            for loc, cellid, sig in gsm_cells
+        ],
+        "wifi_access_points": [
+            {"macAddress": mac, "signalStrength": sig} for mac, sig in wifi_aps
+        ],
+    }
+    result = gclient.geolocate(**kwargs)
+    if "location" in result:
+        return result["location"]["lat"], result["location"]["lng"]
+    else:
+        raise ValueError("google geolocation: " + str(result))
+
+
+if __name__.endswith("__main__"):
+    from datetime import datetime, timezone
+    import sys
+    from .gps303proto import *
+
+    db = connect(sys.argv[1])
+    c = db.cursor()
+    c.execute(
+        """select tstamp, packet from events
+            where proto in (?, ?)""",
+        (WIFI_POSITIONING.PROTO, WIFI_OFFLINE_POSITIONING.PROTO),
+    )
+    init({"googlemaps": {"accesstoken": sys.argv[2]}})
+    count = 0
+    for timestamp, packet in c:
+        obj = parse_message(packet)
+        print(obj)
+        avlat, avlon = lookup(obj.mcc, obj.mnc, obj.gsm_cells, obj.wifi_aps)
+        print(
+            "{} {:+#010.8g},{:+#010.8g}".format(
+                datetime.fromtimestamp(timestamp), avlat, avlon
+            )
+        )
+        count += 1
+        if count > 10:
+            break
index 6924757ec344a7992b8b3aed510f536ecef2c66a..7655f55e4bb095655b41d525aba89cf0a4b12c87 100644 (file)
@@ -15,12 +15,7 @@ log = getLogger("gps303/lookaside")
 
 
 def runserver(conf):
-    if conf.get("lookaside", "backend") == "opencellid":
-        qry = import_module(".opencellid", __package__)
-    else:
-        raise NotImplementedError(
-            "Lookaside only implements opencellid backend"
-        )
+    qry = import_module("." + conf.get("lookaside", "backend"), __package__)
     qry.init(conf)
     zctx = zmq.Context()
     zsub = zctx.socket(zmq.SUB)
@@ -40,14 +35,17 @@ def runserver(conf):
                 datetime.fromtimestamp(zmsg.when).astimezone(tz=timezone.utc),
                 msg,
             )
-            lat, lon = qry.lookup(msg.mcc, msg.gsm_cells, msg.wifi_aps)
-            resp = Resp(
-                imei=zmsg.imei,
-                when=zmsg.when,  # not the current time, but the original!
-                packet=msg.Out(latitude=lat, longitude=lon).packed,
-            )
-            log.debug("Response for lat=%s, lon=%s: %s", lat, lon, resp)
-            zpush.send(resp.packed)
+            try:
+                lat, lon = qry.lookup(msg.mcc, msg.mnc, msg.gsm_cells, msg.wifi_aps)
+                resp = Resp(
+                    imei=zmsg.imei,
+                    when=zmsg.when,  # not the current time, but the original!
+                    packet=msg.Out(latitude=lat, longitude=lon).packed,
+                )
+                log.debug("Response for lat=%s, lon=%s: %s", lat, lon, resp)
+                zpush.send(resp.packed)
+            except Exception as e:
+                log.warning("Lookup for %s resulted in %s", msg, e)
 
     except KeyboardInterrupt:
         pass
index 061b54a26ead78440f4476f39329d7f3ff8aa1e0..55cc943cc1787ddc53a8fc71c001cc95ed7edd8e 100644 (file)
@@ -39,7 +39,7 @@ xmlns="http://www.topografix.com/GPX/1/1">
 for tstamp, packet in c:
     msg = parse_message(packet)
     if isinstance(msg, (WIFI_POSITIONING, WIFI_OFFLINE_POSITIONING)):
-        lat, lon = ocid.lookup(msg.mcc, msg.gsm_cells, msg.wifi_aps)
+        lat, lon = ocid.lookup(msg.mcc, msg.mnc, msg.gsm_cells, msg.wifi_aps)
         if lat is None or lon is None:
             continue
     elif isinstance(msg, (GPS_POSITIONING, GPS_OFFLINE_POSITIONING)):
index 0131dc0305bdb6a4e385f7392470c7aecf5bba52..1932fa6980c32309cea1628feae10478256b4416 100644 (file)
@@ -14,7 +14,7 @@ def init(conf):
     ldb = connect(conf["opencellid"]["dbfn"])
 
 
-def lookup(mcc, gsm_cells, _):
+def lookup(mcc, mnc, gsm_cells, __):
     lc = ldb.cursor()
     lc.execute("""attach database ":memory:" as mem""")
     lc.execute("create table mem.seen (locac int, cellid int, signal int)")
@@ -60,7 +60,7 @@ if __name__.endswith("__main__"):
     init({"opencellid": {"dbfn": sys.argv[2]}})
     for timestamp, packet in c:
         obj = parse_message(packet)
-        avlat, avlon = lookup(obj.mcc, obj.gsm_cells, obj.wifi_aps)
+        avlat, avlon = lookup(obj.mcc, obj.mnc, obj.gsm_cells, obj.wifi_aps)
         print(
             "{} {:+#010.8g},{:+#010.8g}".format(
                 datetime.fromtimestamp(timestamp), avlat, avlon