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");
|
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){
|
ws.onmessage = function(e){
|
||||||
if (typeof e.data != 'string') {
|
if (typeof e.data != 'string') {
|
||||||
console.error("unsupported binary data on websocket; ignoring");
|
console.error("unsupported binary data on websocket; ignoring");
|
||||||
@ -27,15 +54,19 @@
|
|||||||
case "config":
|
case "config":
|
||||||
var config = json.value;
|
var config = json.value;
|
||||||
$.getScript("https://maps.googleapis.com/maps/api/js?key=" + config.google_maps_api_key).done(function(){
|
$.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: {
|
center: {
|
||||||
lat: config.receiver_gps[0],
|
lat: config.receiver_gps[0],
|
||||||
lng: config.receiver_gps[1]
|
lng: config.receiver_gps[1]
|
||||||
},
|
},
|
||||||
zoom: 8
|
zoom: 8
|
||||||
});
|
});
|
||||||
|
processUpdates(updateQueue);
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
|
case "update":
|
||||||
|
processUpdates(json.value);
|
||||||
|
break
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// don't lose exception
|
// don't lose exception
|
||||||
|
@ -3,10 +3,12 @@ from owrx.source import DspManager, CpuUsageThread, SdrService, ClientRegistry
|
|||||||
from owrx.feature import FeatureDetector
|
from owrx.feature import FeatureDetector
|
||||||
from owrx.version import openwebrx_version
|
from owrx.version import openwebrx_version
|
||||||
import json
|
import json
|
||||||
|
from owrx.map import Map
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Client(object):
|
class Client(object):
|
||||||
def __init__(self, conn):
|
def __init__(self, conn):
|
||||||
self.conn = conn
|
self.conn = conn
|
||||||
@ -165,9 +167,17 @@ class MapConnection(Client):
|
|||||||
pm = PropertyManager.getSharedInstance()
|
pm = PropertyManager.getSharedInstance()
|
||||||
self.write_config(pm.collect("google_maps_api_key", "receiver_gps").__dict__())
|
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):
|
def write_config(self, cfg):
|
||||||
self.protected_send({"type":"config","value":cfg})
|
self.protected_send({"type":"config","value":cfg})
|
||||||
|
|
||||||
|
def write_update(self, update):
|
||||||
|
self.protected_send({"type":"update","value":update})
|
||||||
|
|
||||||
class WebSocketMessageHandler(object):
|
class WebSocketMessageHandler(object):
|
||||||
def __init__(self):
|
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
|
from datetime import datetime, timedelta
|
||||||
import logging
|
import logging
|
||||||
import threading
|
import threading
|
||||||
|
from owrx.map import Map, LatLngLocation
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -14,18 +15,22 @@ class DmrCache(object):
|
|||||||
if DmrCache.sharedInstance is None:
|
if DmrCache.sharedInstance is None:
|
||||||
DmrCache.sharedInstance = DmrCache()
|
DmrCache.sharedInstance = DmrCache()
|
||||||
return DmrCache.sharedInstance
|
return DmrCache.sharedInstance
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.cache = {}
|
self.cache = {}
|
||||||
self.cacheTimeout = timedelta(seconds = 86400)
|
self.cacheTimeout = timedelta(seconds = 86400)
|
||||||
|
|
||||||
def isValid(self, key):
|
def isValid(self, key):
|
||||||
if not key in self.cache: return False
|
if not key in self.cache: return False
|
||||||
entry = self.cache[key]
|
entry = self.cache[key]
|
||||||
return entry["timestamp"] + self.cacheTimeout > datetime.now()
|
return entry["timestamp"] + self.cacheTimeout > datetime.now()
|
||||||
|
|
||||||
def put(self, key, value):
|
def put(self, key, value):
|
||||||
self.cache[key] = {
|
self.cache[key] = {
|
||||||
"timestamp": datetime.now(),
|
"timestamp": datetime.now(),
|
||||||
"data": value
|
"data": value
|
||||||
}
|
}
|
||||||
|
|
||||||
def get(self, key):
|
def get(self, key):
|
||||||
if not self.isValid(key): return None
|
if not self.isValid(key): return None
|
||||||
return self.cache[key]["data"]
|
return self.cache[key]["data"]
|
||||||
@ -34,6 +39,7 @@ class DmrCache(object):
|
|||||||
class DmrMetaEnricher(object):
|
class DmrMetaEnricher(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.threads = {}
|
self.threads = {}
|
||||||
|
|
||||||
def downloadRadioIdData(self, id):
|
def downloadRadioIdData(self, id):
|
||||||
cache = DmrCache.getSharedInstance()
|
cache = DmrCache.getSharedInstance()
|
||||||
try:
|
try:
|
||||||
@ -44,6 +50,7 @@ class DmrMetaEnricher(object):
|
|||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
cache.put(id, None)
|
cache.put(id, None)
|
||||||
del self.threads[id]
|
del self.threads[id]
|
||||||
|
|
||||||
def enrich(self, meta):
|
def enrich(self, meta):
|
||||||
if not PropertyManager.getSharedInstance()["digital_voice_dmr_id_lookup"]: return None
|
if not PropertyManager.getSharedInstance()["digital_voice_dmr_id_lookup"]: return None
|
||||||
if not "source" in meta: return None
|
if not "source" in meta: return None
|
||||||
@ -60,9 +67,18 @@ class DmrMetaEnricher(object):
|
|||||||
return None
|
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):
|
class MetaParser(object):
|
||||||
enrichers = {
|
enrichers = {
|
||||||
"DMR": DmrMetaEnricher()
|
"DMR": DmrMetaEnricher(),
|
||||||
|
"YSF": YsfMetaEnricher()
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, handler):
|
def __init__(self, handler):
|
||||||
|
Loading…
Reference in New Issue
Block a user