introduce source classes for the map

This commit is contained in:
Jakob Ketterl 2023-09-06 16:36:38 +02:00
parent abc5cd177e
commit 26b8423193
7 changed files with 77 additions and 30 deletions

View file

@ -1,6 +1,6 @@
from csdr.module import PickleModule
from math import sqrt, atan2, pi, floor, acos, cos
from owrx.map import LatLngLocation, IncrementalUpdate, Location, Map
from owrx.map import LatLngLocation, IncrementalUpdate, Location, Map, Source
from owrx.metrics import Metrics, CounterMetric
from datetime import datetime, timedelta
from enum import Enum
@ -65,6 +65,17 @@ class AdsbLocation(AirplaneLocation):
return timedelta(seconds=30)
class IcaoSource(Source):
def __init__(self, icao: str):
self.icao = icao
def getKey(self) -> str:
return "icao:{}".format(self.icao)
def __dict__(self):
return {"icao": self.icao}
class CprRecordType(Enum):
AIR = ("air", 360)
GROUND = ("ground", 90)
@ -282,7 +293,7 @@ class ModeSParser(PickleModule):
if "icao" in message and AirplaneLocation.mapKeys & message.keys():
data = {k: message[k] for k in AirplaneLocation.mapKeys if k in message}
loc = AdsbLocation(data)
Map.getSharedInstance().updateLocation({"icao": message['icao']}, loc, "ADS-B", None)
Map.getSharedInstance().updateLocation(IcaoSource(message['icao']), loc, "ADS-B", None)
return message

View file

@ -1,4 +1,4 @@
from owrx.map import Map, LatLngLocation
from owrx.map import Map, LatLngLocation, Source
from owrx.metrics import Metrics, CounterMetric
from owrx.bands import Bandplan
from datetime import datetime, timezone
@ -155,6 +155,20 @@ class AprsLocation(LatLngLocation):
return res
class AprsSource(Source):
def __init__(self, source):
self.source = source
def getKey(self) -> str:
callsign = self.source["callsign"]
if "ssid" in self.source:
callsign += "-{}".format(self.source["ssid"])
return "aprs:{}".format(callsign)
def __dict__(self):
return self.source
class AprsParser(PickleModule):
def __init__(self):
super().__init__()
@ -215,7 +229,7 @@ class AprsParser(PickleModule):
source["item"] = mapData["item"]
elif mapData["type"] == "object" and "object" in mapData:
source["object"] = mapData["object"]
Map.getSharedInstance().updateLocation(source, loc, "APRS", self.band)
Map.getSharedInstance().updateLocation(AprsSource(source), loc, "APRS", self.band)
def hasCompressedCoordinates(self, raw):
return raw[0] == "/" or raw[0] == "\\"

View file

@ -2,13 +2,24 @@ from pycsdr.modules import ExecModule
from pycsdr.types import Format
from csdr.module import JsonParser
from owrx.adsb.modes import AirplaneLocation
from owrx.map import Map
from owrx.map import Map, Source
class HfdlAirplaneLocation(AirplaneLocation):
pass
class HfdlSource(Source):
def __init__(self, flight):
self.flight = flight
def getKey(self) -> str:
return "hfdl:{}".format(self.flight)
def __dict__(self):
return {"flight": self.flight}
class DumpHFDLModule(ExecModule):
def __init__(self):
super().__init__(
@ -42,5 +53,5 @@ class HFDLMessageParser(JsonParser):
if "pos" in hfnpdu:
pos = hfnpdu['pos']
if abs(pos['lat']) <= 90 and abs(pos['lon']) <= 180:
Map.getSharedInstance().updateLocation({"flight": hfnpdu["flight_id"]}, HfdlAirplaneLocation(pos), "HFDL")
Map.getSharedInstance().updateLocation(HfdlSource(hfnpdu["flight_id"]), HfdlAirplaneLocation(pos), "HFDL")
return msg

View file

@ -3,7 +3,7 @@ from owrx.audio.chopper import AudioChopperParser
import re
from js8py import Js8
from js8py.frames import Js8FrameHeartbeat, Js8FrameCompound
from owrx.map import Map, LocatorLocation
from owrx.map import Map, LocatorLocation, CallsignSource
from owrx.metrics import Metrics, CounterMetric
from owrx.config import Config
from abc import ABCMeta, abstractmethod
@ -103,7 +103,7 @@ class Js8Parser(AudioChopperParser):
if (isinstance(frame, Js8FrameHeartbeat) or isinstance(frame, Js8FrameCompound)) and frame.grid:
Map.getSharedInstance().updateLocation(
frame.source, LocatorLocation(frame.grid), "JS8", band
CallsignSource(**frame.source), LocatorLocation(frame.grid), "JS8", band
)
ReportingEngine.getSharedInstance().spot(
{

View file

@ -1,7 +1,7 @@
from datetime import datetime, timedelta
from owrx.config import Config
from owrx.bands import Band
from abc import abstractmethod, ABCMeta
from abc import abstractmethod, ABC, ABCMeta
import threading
import time
import sys
@ -22,6 +22,15 @@ class Location(object):
}
class Source(ABC):
@abstractmethod
def getKey(self) -> str:
pass
def __dict__(self):
return {}
class Map(object):
sharedInstance = None
creationLock = threading.Lock()
@ -67,7 +76,7 @@ class Map(object):
client.write_update(
[
{
"source": record["source"],
"source": record["source"].__dict__(),
"location": record["location"].__dict__(),
"lastseen": record["updated"].timestamp() * 1000,
"mode": record["mode"],
@ -83,18 +92,9 @@ class Map(object):
except ValueError:
pass
def _sourceToKey(self, source):
if "ssid" in source:
return "{callsign}-{ssid}".format(**source)
elif "icao" in source:
return source["icao"]
elif "flight" in source:
return source["flight"]
return source["callsign"]
def updateLocation(self, source, loc: Location, mode: str, band: Band = None):
def updateLocation(self, source: Source, loc: Location, mode: str, band: Band = None):
ts = datetime.now()
key = self._sourceToKey(source)
key = source.getKey()
with self.positionsLock:
if isinstance(loc, IncrementalUpdate) and key in self.positions:
loc.update(self.positions[key]["location"])
@ -102,7 +102,7 @@ class Map(object):
self.broadcast(
[
{
"source": source,
"source": source.__dict__(),
"location": loc.__dict__(),
"lastseen": ts.timestamp() * 1000,
"mode": mode,
@ -111,14 +111,14 @@ class Map(object):
]
)
def touchLocation(self, source):
def touchLocation(self, source: Source):
# not implemented on the client side yet, so do not use!
ts = datetime.now()
key = self._sourceToKey(source)
key = source.getKey()
with self.positionsLock:
if key in self.positions:
self.positions[key]["updated"] = ts
self.broadcast([{"source": source, "lastseen": ts.timestamp() * 1000}])
self.broadcast([{"source": source.__dict__(), "lastseen": ts.timestamp() * 1000}])
def removeLocation(self, key):
with self.positionsLock:
@ -172,3 +172,14 @@ class IncrementalUpdate(Location, metaclass=ABCMeta):
@abstractmethod
def update(self, previousLocation: Location):
pass
class CallsignSource(Source):
def __init__(self, callsign: str):
self.callsign = callsign
def getKey(self) -> str:
return "callsign:{}".format(self.callsign)
def __dict__(self):
return {"callsign": self.callsign}

View file

@ -11,7 +11,7 @@ from urllib.error import HTTPError
from csdr.module import PickleModule
from owrx.aprs import AprsParser, AprsLocation
from owrx.config import Config
from owrx.map import Map, LatLngLocation
from owrx.map import Map, LatLngLocation, CallsignSource
from owrx.bands import Bandplan
logger = logging.getLogger(__name__)
@ -129,7 +129,7 @@ class DigihamEnricher(Enricher, metaclass=ABCMeta):
callsign = self.getCallsign(meta)
if callsign is not None and "lat" in meta and "lon" in meta:
loc = LatLngLocation(meta["lat"], meta["lon"])
Map.getSharedInstance().updateLocation({"callsign": callsign}, loc, mode, self.parser.getBand())
Map.getSharedInstance().updateLocation(CallsignSource(callsign), loc, mode, self.parser.getBand())
return meta
@abstractmethod
@ -202,7 +202,7 @@ class DStarEnricher(DigihamEnricher):
if "ourcall" in meta:
# send location info to map as well (it will show up with the correct symbol there!)
loc = AprsLocation(data)
Map.getSharedInstance().updateLocation({"callsign": meta["ourcall"]}, loc, "DPRS", self.parser.getBand())
Map.getSharedInstance().updateLocation(CallsignSource(meta["ourcall"]), loc, "DPRS", self.parser.getBand())
except Exception:
logger.exception("Error while parsing DPRS data")

View file

@ -1,6 +1,6 @@
from datetime import datetime, timezone
from typing import List
from owrx.map import Map, LocatorLocation
from owrx.map import Map, LocatorLocation, CallsignSource
from owrx.metrics import Metrics, CounterMetric
from owrx.reporting import ReportingEngine
from owrx.audio import AudioChopperProfile, StaticProfileSource, ConfigWiredProfileSource
@ -289,7 +289,7 @@ class WsjtParser(AudioChopperParser):
self.pushDecode(mode, band)
if "source" in out and "locator" in out:
Map.getSharedInstance().updateLocation(
out["source"], LocatorLocation(out["locator"]), mode, band
CallsignSource(**out["source"]), LocatorLocation(out["locator"]), mode, band
)
ReportingEngine.getSharedInstance().spot(out)