display locations parsed from ysf on map

This commit is contained in:
Jakob Ketterl 2019-07-01 21:20:53 +02:00
parent 272caa7100
commit 3b2b51f07c
4 changed files with 121 additions and 2 deletions

View File

@ -12,6 +12,33 @@
ws.send("SERVER DE CLIENT client=map.js type=map");
};
var map;
var markers = {};
var updateQueue = [];
var processUpdates = function(updates) {
if (!map) {
updateQueue = updateQueue.concat(updates);
return;
}
updates.forEach(function(update){
// TODO maidenhead locator implementation
if (update.location.type != 'latlon') return;
var pos = new google.maps.LatLng(update.location.lat, update.location.lon)
if (markers[update.callsign]) {
console.info("updating");
markers[update.callsign].setPosition(pos);
} else {
console.info("initializing");
markers[update.callsign] = new google.maps.Marker({
position: pos,
map: map,
title: update.callsign
});
}
});
}
ws.onmessage = function(e){
if (typeof e.data != 'string') {
console.error("unsupported binary data on websocket; ignoring");
@ -27,15 +54,19 @@
case "config":
var config = json.value;
$.getScript("https://maps.googleapis.com/maps/api/js?key=" + config.google_maps_api_key).done(function(){
var map = new google.maps.Map($('body')[0], {
map = new google.maps.Map($('body')[0], {
center: {
lat: config.receiver_gps[0],
lng: config.receiver_gps[1]
},
zoom: 8
});
processUpdates(updateQueue);
})
break
case "update":
processUpdates(json.value);
break
}
} catch (e) {
// don't lose exception

View File

@ -3,10 +3,12 @@ from owrx.source import DspManager, CpuUsageThread, SdrService, ClientRegistry
from owrx.feature import FeatureDetector
from owrx.version import openwebrx_version
import json
from owrx.map import Map
import logging
logger = logging.getLogger(__name__)
class Client(object):
def __init__(self, conn):
self.conn = conn
@ -165,9 +167,17 @@ class MapConnection(Client):
pm = PropertyManager.getSharedInstance()
self.write_config(pm.collect("google_maps_api_key", "receiver_gps").__dict__())
Map.getSharedInstance().addClient(self)
def close(self):
Map.getSharedInstance().removeClient(self)
super().close()
def write_config(self, cfg):
self.protected_send({"type":"config","value":cfg})
def write_update(self, update):
self.protected_send({"type":"update","value":update})
class WebSocketMessageHandler(object):
def __init__(self):

62
owrx/map.py Normal file
View File

@ -0,0 +1,62 @@
from datetime import datetime
class Location(object):
def __dict__(self):
return {}
class Map(object):
sharedInstance = None
@staticmethod
def getSharedInstance():
if Map.sharedInstance is None:
Map.sharedInstance = Map()
return Map.sharedInstance
def __init__(self):
self.clients = []
self.positions = {}
super().__init__()
def broadcast(self, update):
for c in self.clients:
c.write_update(update)
def addClient(self, client):
self.clients.append(client)
client.write_update([{"callsign": callsign, "location": record["loc"].__dict__()} for (callsign, record) in self.positions.items()])
def removeClient(self, client):
try:
self.clients.remove(client)
except ValueError:
pass
def updateLocation(self, callsign, loc: Location):
self.positions[callsign] = {"loc": loc, "updated": datetime.now()}
self.broadcast([{"callsign": callsign, "location": loc.__dict__()}])
class LatLngLocation(Location):
def __init__(self, lat: float, lon: float):
self.lat = lat
self.lon = lon
def __dict__(self):
return {
"type":"latlon",
"lat":self.lat,
"lon":self.lon
}
class LocatorLocation(Location):
def __init__(self, locator: str):
self.locator = locator
def __dict__(self):
return {
"type":"locator",
"locator":self.locator
}

View File

@ -4,6 +4,7 @@ import json
from datetime import datetime, timedelta
import logging
import threading
from owrx.map import Map, LatLngLocation
logger = logging.getLogger(__name__)
@ -14,18 +15,22 @@ class DmrCache(object):
if DmrCache.sharedInstance is None:
DmrCache.sharedInstance = DmrCache()
return DmrCache.sharedInstance
def __init__(self):
self.cache = {}
self.cacheTimeout = timedelta(seconds = 86400)
def isValid(self, key):
if not key in self.cache: return False
entry = self.cache[key]
return entry["timestamp"] + self.cacheTimeout > datetime.now()
def put(self, key, value):
self.cache[key] = {
"timestamp": datetime.now(),
"data": value
}
def get(self, key):
if not self.isValid(key): return None
return self.cache[key]["data"]
@ -34,6 +39,7 @@ class DmrCache(object):
class DmrMetaEnricher(object):
def __init__(self):
self.threads = {}
def downloadRadioIdData(self, id):
cache = DmrCache.getSharedInstance()
try:
@ -44,6 +50,7 @@ class DmrMetaEnricher(object):
except json.JSONDecodeError:
cache.put(id, None)
del self.threads[id]
def enrich(self, meta):
if not PropertyManager.getSharedInstance()["digital_voice_dmr_id_lookup"]: return None
if not "source" in meta: return None
@ -60,9 +67,18 @@ class DmrMetaEnricher(object):
return None
class YsfMetaEnricher(object):
def enrich(self, meta):
if "source" in meta and "lat" in meta and "lon" in meta:
# TODO parsing the float values should probably happen earlier
Map.getSharedInstance().updateLocation(meta["source"], LatLngLocation(float(meta["lat"]), float(meta["lon"])))
return None
class MetaParser(object):
enrichers = {
"DMR": DmrMetaEnricher()
"DMR": DmrMetaEnricher(),
"YSF": YsfMetaEnricher()
}
def __init__(self, handler):