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, 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 oldmask = umask(0o117)
55 zpub.bind(conf.get("rectifier", "publishurl"))
60 zmsg = Bcast(zsub.recv())
61 msg = common.parse_message(
62 zmsg.proto, zmsg.packet, is_incoming=zmsg.is_incoming
65 "IMEI %s from %s at %s: %s",
68 datetime.fromtimestamp(zmsg.when).astimezone(tz=timezone.utc),
71 rect = msg.rectified()
72 log.debug("rectified: %s", rect)
73 if isinstance(rect, (CoordReport, StatusReport)):
74 zpub.send(Rept(imei=zmsg.imei, payload=rect.json).packed)
75 elif isinstance(rect, HintReport):
77 lat, lon, acc = qry.lookup(
81 list((mac, strng) for _, mac, strng in rect.wifi_aps),
84 "Approximated lat=%s, lon=%s, acc=%s for %s",
90 if proto_needanswer.get(zmsg.proto, False):
93 when=zmsg.when, # not the current time, but the original!
94 packet=msg.Out(latitude=lat, longitude=lon).packed,
96 log.debug("Sending reponse %s", resp)
97 zpush.send(resp.packed)
100 battery_percentage=rect.battery_percentage,
108 log.debug("Sending report %s", rept)
115 except Exception as e:
117 "Lookup for %s rectified as %s resulted in %s",
123 except KeyboardInterrupt:
127 zctx.destroy() # type: ignore
131 if __name__.endswith("__main__"):
132 runserver(common.init(log))