]> www.average.org Git - loctrkd.git/commitdiff
Convert recitifier to multiprotocol support
authorEugene Crosser <crosser@average.org>
Thu, 28 Jul 2022 22:04:57 +0000 (00:04 +0200)
committerEugene Crosser <crosser@average.org>
Thu, 28 Jul 2022 22:04:57 +0000 (00:04 +0200)
loctrkd/beesure.py
loctrkd/common.py
loctrkd/rectifier.py
loctrkd/zmsg.py
loctrkd/zx303proto.py

index baf14dbee9600eb25252f9d44ea38c80fac0890a..ad351cb0126b3c3616169802e36150d39b1a2371 100755 (executable)
@@ -23,6 +23,12 @@ from typing import (
 from types import SimpleNamespace
 
 from .protomodule import ProtoClass
 from types import SimpleNamespace
 
 from .protomodule import ProtoClass
+from .common import (
+    CoordReport,
+    HintReport,
+    StatusReport,
+    Report,
+)
 
 __all__ = (
     "Stream",
 
 __all__ = (
     "Stream",
@@ -313,7 +319,7 @@ class _LOC_DATA(BeeSurePkt):
                 (self, "pedometer", int),
                 (self, "tubmling_times", int),
                 (self, "device_status", lambda x: int(x, 16)),
                 (self, "pedometer", int),
                 (self, "tubmling_times", int),
                 (self, "device_status", lambda x: int(x, 16)),
-                (self, "base_stations_number", int),
+                (self, "gsm_cells_number", int),
                 (self, "connect_base_station_number", int),
                 (self, "mcc", int),
                 (self, "mnc", int),
                 (self, "connect_base_station_number", int),
                 (self, "mcc", int),
                 (self, "mnc", int),
@@ -323,11 +329,11 @@ class _LOC_DATA(BeeSurePkt):
             setattr(obj, attr, func(val))  # type: ignore
         rest_args = args[20:]
         # (area_id, cell_id, strength)*
             setattr(obj, attr, func(val))  # type: ignore
         rest_args = args[20:]
         # (area_id, cell_id, strength)*
-        self.base_stations = [
-            tuple(int(el) for el in rest_args[i * 3 : 3 + i * 3])
-            for i in range(self.base_stations_number)
+        self.gsm_cells: List[Tuple[int, int, int]] = [
+            tuple(int(el) for el in rest_args[i * 3 : 3 + i * 3])  # type: ignore
+            for i in range(self.gsm_cells_number)
         ]
         ]
-        rest_args = rest_args[3 * self.base_stations_number :]
+        rest_args = rest_args[3 * self.gsm_cells_number :]
         self.wifi_aps_number = int(rest_args[0])
         # (SSID, MAC, strength)*
         self.wifi_aps = [
         self.wifi_aps_number = int(rest_args[0])
         # (SSID, MAC, strength)*
         self.wifi_aps = [
@@ -351,10 +357,9 @@ class _LOC_DATA(BeeSurePkt):
         self.latitude = p.lat * p.nors
         self.longitude = p.lon * p.eorw
 
         self.latitude = p.lat * p.nors
         self.longitude = p.lon * p.eorw
 
-    def rectified(self) -> SimpleNamespace:  # JSON-able dict
+    def rectified(self) -> Report:
         if self.gps_valid:
         if self.gps_valid:
-            return SimpleNamespace(
-                type="location",
+            return CoordReport(
                 devtime=str(self.devtime),
                 battery_percentage=self.battery_percentage,
                 accuracy=self.positioning_accuracy,
                 devtime=str(self.devtime),
                 battery_percentage=self.battery_percentage,
                 accuracy=self.positioning_accuracy,
@@ -365,13 +370,12 @@ class _LOC_DATA(BeeSurePkt):
                 longitude=self.longitude,
             )
         else:
                 longitude=self.longitude,
             )
         else:
-            return SimpleNamespace(
-                type="approximate_location",
+            return HintReport(
                 devtime=str(self.devtime),
                 battery_percentage=self.battery_percentage,
                 mcc=self.mcc,
                 mnc=self.mnc,
                 devtime=str(self.devtime),
                 battery_percentage=self.battery_percentage,
                 mcc=self.mcc,
                 mnc=self.mnc,
-                base_stations=self.base_stations,
+                gsm_cells=self.gsm_cells,
                 wifi_aps=self.wifi_aps,
             )
 
                 wifi_aps=self.wifi_aps,
             )
 
@@ -618,7 +622,7 @@ def parse_message(packet: bytes, is_incoming: bool = True) -> BeeSurePkt:
 
 def exposed_protos() -> List[Tuple[str, bool]]:
     return [
 
 def exposed_protos() -> List[Tuple[str, bool]]:
     return [
-        (proto_name(cls), False)
+        (proto_name(cls)[:16], False)
         for cls in CLASSES.values()
         if hasattr(cls, "rectified")
     ]
         for cls in CLASSES.values()
         if hasattr(cls, "rectified")
     ]
index f112fbd53a51176e279b77c01cc05e6f32529bd2..30a17194ffcb5f645bc01d43cf265261a718e339 100644 (file)
@@ -3,11 +3,13 @@
 from configparser import ConfigParser
 from importlib import import_module
 from getopt import getopt
 from configparser import ConfigParser
 from importlib import import_module
 from getopt import getopt
+from json import dumps
 from logging import Formatter, getLogger, Logger, StreamHandler, DEBUG, INFO
 from logging.handlers import SysLogHandler
 from pkg_resources import get_distribution, DistributionNotFound
 from sys import argv, stderr, stdout
 from typing import Any, cast, Dict, List, Optional, Tuple, Union
 from logging import Formatter, getLogger, Logger, StreamHandler, DEBUG, INFO
 from logging.handlers import SysLogHandler
 from pkg_resources import get_distribution, DistributionNotFound
 from sys import argv, stderr, stdout
 from typing import Any, cast, Dict, List, Optional, Tuple, Union
+from types import SimpleNamespace
 
 from .protomodule import ProtoModule
 
 
 from .protomodule import ProtoModule
 
@@ -76,3 +78,69 @@ def parse_message(proto: str, packet: bytes, is_incoming: bool = True) -> Any:
 
 def exposed_protos() -> List[Tuple[str, bool]]:
     return [item for pmod in pmods for item in pmod.exposed_protos()]
 
 def exposed_protos() -> List[Tuple[str, bool]]:
     return [item for pmod in pmods for item in pmod.exposed_protos()]
+
+
+class Report(SimpleNamespace):
+    TYPE: str
+
+    @property
+    def json(self) -> str:
+        self.type = self.TYPE
+        return dumps(self.__dict__)
+
+
+class CoordReport(Report):
+    TYPE = "location"
+
+    def __init__(
+        self,
+        *,
+        devtime: str,
+        battery_percentage: int,
+        accuracy: float,
+        altitude: float,
+        speed: float,
+        direction: float,
+        latitude: float,
+        longitude: float
+    ) -> None:
+        super().__init__(
+            devtime=devtime,
+            battery_percentage=battery_percentage,
+            accuracy=accuracy,
+            altitude=altitude,
+            speed=speed,
+            direction=direction,
+            latitude=latitude,
+            longitude=longitude,
+        )
+
+
+class HintReport(Report):
+    TYPE = "approximate_location"
+
+    def __init__(
+        self,
+        *,
+        devtime: str,
+        battery_percentage: int,
+        mcc: int,
+        mnc: int,
+        gsm_cells: List[Tuple[int, int, int]],
+        wifi_aps: List[Tuple[str, str, int]]
+    ) -> None:
+        super().__init__(
+            devtime=devtime,
+            battery_percentage=battery_percentage,
+            mcc=mcc,
+            mnc=mnc,
+            gsm_cells=gsm_cells,
+            wifi_aps=wifi_aps,
+        )
+
+
+class StatusReport(Report):
+    TYPE = "status"
+
+    def __init__(self, *, battery_percentage: int) -> None:
+        super().__init__(battery_percentage=battery_percentage)
index ec8baa1a5ab33afaed9fc64e56959cc4e185cd71..e4f29b2936a40258d664521ba85fb4267ff38da8 100644 (file)
@@ -9,7 +9,8 @@ from struct import pack
 import zmq
 
 from . import common
 import zmq
 
 from . import common
-from .zmsg import Bcast, Report, Resp, topic
+from .common import CoordReport, HintReport, StatusReport, Report
+from .zmsg import Bcast, Rept, Resp, topic
 
 log = getLogger("loctrkd/rectifier")
 
 
 log = getLogger("loctrkd/rectifier")
 
@@ -42,24 +43,48 @@ def runserver(conf: ConfigParser) -> None:
                 datetime.fromtimestamp(zmsg.when).astimezone(tz=timezone.utc),
                 msg,
             )
                 datetime.fromtimestamp(zmsg.when).astimezone(tz=timezone.utc),
                 msg,
             )
-            rect = msg.rectified()
+            rect: Report = msg.rectified()
             log.debug("rectified: %s", rect)
             log.debug("rectified: %s", rect)
-            if rect.type == "approximate_location":
+            if isinstance(rect, (CoordReport, StatusReport)):
+                zpub.send(Rept(imei=zmsg.imei, payload=rect.json).packed)
+            elif isinstance(rect, HintReport):
                 try:
                     lat, lon = qry.lookup(
                 try:
                     lat, lon = qry.lookup(
-                        rect.mcc, rect.mnc, rect.base_stations, rect.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,
+                        rect.mcc, rect.mnc, rect.gsm_cells, rect.wifi_aps
                     )
                     log.debug(
                     )
                     log.debug(
-                        "Response for lat=%s, lon=%s: %s", lat, lon, resp
+                        "Approximated lat=%s, lon=%s for %s", lat, lon, rect
+                    )
+                    if proto_needanswer.get(zmsg.proto, False):
+                        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("Sending reponse %s", resp)
+                        zpush.send(resp.packed)
+                    zpub.send(
+                        Rept(
+                            imei=zmsg.imei,
+                            payload=CoordReport(
+                                devtime=rect.devtime,
+                                battery_percentage=rect.battery_percentage,
+                                accuracy=-1,
+                                altitude=-1,
+                                speed=-1,
+                                direction=-1,
+                                latitude=lat,
+                                longitude=lon,
+                            ).json,
+                        ).packed
                     )
                     )
-                    zpush.send(resp.packed)
                 except Exception as e:
                 except Exception as e:
-                    log.warning("Lookup for %s resulted in %s", msg, e)
+                    log.warning(
+                        "Lookup for %s rectified as %s resulted in %s",
+                        msg,
+                        rect,
+                        e,
+                    )
 
     except KeyboardInterrupt:
         zsub.close()
 
     except KeyboardInterrupt:
         zsub.close()
index 9dae60540f46019957a72121700c6ada5df081de..4da88d2f6754e7e78db97ef8ecc9e989dcd1475c 100644 (file)
@@ -168,7 +168,7 @@ class Resp(_Zmsg):
         self.packet = buffer[24:]
 
 
         self.packet = buffer[24:]
 
 
-class Report(_Zmsg):
+class Rept(_Zmsg):
     """Broadcast Zzmq message with "rectified" proto-agnostic json data"""
 
     KWARGS = (("imei", None), ("payload", ""))
     """Broadcast Zzmq message with "rectified" proto-agnostic json data"""
 
     KWARGS = (("imei", None), ("payload", ""))
index 236f5daa16a1252f3203e660e1718370148465a5..2a0ede6991c89b9c46ef56fe3ad344d5c7b506a3 100755 (executable)
@@ -32,6 +32,7 @@ from typing import (
     Union,
 )
 
     Union,
 )
 
+from .common import CoordReport, HintReport, StatusReport
 from .protomodule import ProtoClass
 
 __all__ = (
 from .protomodule import ProtoClass
 
 __all__ = (
@@ -364,10 +365,12 @@ class _GPS_POSITIONING(GPS303Pkt):
         ttup = (tup[0] % 100,) + tup[1:6]
         return pack("BBBBBB", *ttup)
 
         ttup = (tup[0] % 100,) + tup[1:6]
         return pack("BBBBBB", *ttup)
 
-    def rectified(self) -> SimpleNamespace:  # JSON-able dict
-        return SimpleNamespace(
-            type="location",
+    def rectified(self) -> CoordReport:  # JSON-able dict
+        return CoordReport(
             devtime=str(self.devtime),
             devtime=str(self.devtime),
+            battery_percentage=-1,
+            accuracy=-1.0,
+            altitude=-1.0,
             speed=self.speed,
             direction=self.heading,
             latitude=self.latitude,
             speed=self.speed,
             direction=self.heading,
             latitude=self.latitude,
@@ -412,6 +415,9 @@ class STATUS(GPS303Pkt):
     def out_encode(self) -> bytes:  # Set interval in minutes
         return pack("B", self.upload_interval)
 
     def out_encode(self) -> bytes:  # Set interval in minutes
         return pack("B", self.upload_interval)
 
+    def rectified(self) -> StatusReport:
+        return StatusReport(battery_percentage=self.batt)
+
 
 class HIBERNATION(GPS303Pkt):  # Server can send to send devicee to sleep
     PROTO = 0x14
 
 class HIBERNATION(GPS303Pkt):  # Server can send to send devicee to sleep
     PROTO = 0x14
@@ -490,14 +496,14 @@ class _WIFI_POSITIONING(GPS303Pkt):
             ]
         )
 
             ]
         )
 
-    def rectified(self) -> SimpleNamespace:  # JSON-able dict
-        return SimpleNamespace(
-            type="approximate_location",
+    def rectified(self) -> HintReport:
+        return HintReport(
             devtime=str(self.devtime),
             devtime=str(self.devtime),
+            battery_percentage=-1,
             mcc=self.mcc,
             mnc=self.mnc,
             mcc=self.mcc,
             mnc=self.mnc,
-            base_stations=self.gsm_cells,
-            wifi_aps=self.wifi_aps,
+            gsm_cells=self.gsm_cells,
+            wifi_aps=[("<UNKNOWN>", mac, sig) for mac, sig in self.wifi_aps],
         )
 
 
         )
 
 
@@ -887,7 +893,7 @@ def parse_message(packet: bytes, is_incoming: bool = True) -> GPS303Pkt:
 
 def exposed_protos() -> List[Tuple[str, bool]]:
     return [
 
 def exposed_protos() -> List[Tuple[str, bool]]:
     return [
-        (proto_name(cls), cls.RESPOND is Respond.EXT)
+        (proto_name(cls)[:16], cls.RESPOND is Respond.EXT)
         for cls in CLASSES.values()
         if hasattr(cls, "rectified")
     ]
         for cls in CLASSES.values()
         if hasattr(cls, "rectified")
     ]