display locations parsed from ysf on map
This commit is contained in:
parent
272caa7100
commit
3b2b51f07c
@ -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
|
||||
|
@ -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
62
owrx/map.py
Normal 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
|
||||
}
|
18
owrx/meta.py
18
owrx/meta.py
@ -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):
|
||||
|
Loading…
Reference in New Issue
Block a user