1 """ Estimate coordinates from WIFI_POSITIONING and send back """
3 from configparser import ConfigParser
4 from datetime import datetime, timezone
5 from importlib import import_module
6 from logging import getLogger
8 from struct import pack
9 from typing import cast, List, Tuple
13 from .common import CoordReport, HintReport, StatusReport, Report
14 from .zmsg import Bcast, Rept, Resp, topic
16 log = getLogger("loctrkd/rectifier")
21 def init(conf: ConfigParser) -> None:
32 gsm_cells: List[Tuple[int, int, int]],
33 wifi_aps: List[Tuple[str, int]],
34 ) -> Tuple[float, float]:
38 def runserver(conf: ConfigParser) -> None:
41 import_module("." + conf.get("rectifier", "lookaside"), __package__),
44 proto_needanswer = dict(common.exposed_protos())
45 # Is this https://github.com/zeromq/pyzmq/issues/1627 still not fixed?!
46 zctx = zmq.Context() # type: ignore
47 zsub = zctx.socket(zmq.SUB) # type: ignore
48 zsub.connect(conf.get("collector", "publishurl"))
49 for proto in proto_needanswer.keys():
50 zsub.setsockopt(zmq.SUBSCRIBE, topic(proto))
51 zpush = zctx.socket(zmq.PUSH) # type: ignore
52 zpush.connect(conf.get("collector", "listenurl"))
53 zpub = zctx.socket(zmq.PUB) # type: ignore
54 zpub.bind(conf.get("rectifier", "publishurl"))
58 zmsg = Bcast(zsub.recv())
59 msg = common.parse_message(
60 zmsg.proto, zmsg.packet, is_incoming=zmsg.is_incoming
63 "IMEI %s from %s at %s: %s",
66 datetime.fromtimestamp(zmsg.when).astimezone(tz=timezone.utc),
69 rect: Report = msg.rectified()
70 log.debug("rectified: %s", rect)
71 if isinstance(rect, (CoordReport, StatusReport)):
72 zpub.send(Rept(imei=zmsg.imei, payload=rect.json).packed)
73 elif isinstance(rect, HintReport):
75 lat, lon = qry.lookup(
79 list((mac, strng) for _, mac, strng in rect.wifi_aps),
82 "Approximated lat=%s, lon=%s for %s", lat, lon, rect
84 if proto_needanswer.get(zmsg.proto, False):
87 when=zmsg.when, # not the current time, but the original!
88 packet=msg.Out(latitude=lat, longitude=lon).packed,
90 log.debug("Sending reponse %s", resp)
91 zpush.send(resp.packed)
94 battery_percentage=rect.battery_percentage,
102 log.debug("Sending report %s", rept)
109 except Exception as e:
111 "Lookup for %s rectified as %s resulted in %s",
117 except KeyboardInterrupt:
121 zctx.destroy() # type: ignore
125 if __name__.endswith("__main__"):
126 runserver(common.init(log))