mirror of
https://github.com/ha7ilm/openwebrx.git
synced 2026-01-23 16:50:24 +01:00
apply ttl approach to all locations
This commit is contained in:
parent
22b6d3e645
commit
26896cf2d5
|
|
@ -30,8 +30,6 @@ $(function(){
|
|||
var receiverMarker;
|
||||
var updateQueue = [];
|
||||
|
||||
// reasonable default; will be overriden by server
|
||||
var retention_time = 2 * 60 * 60 * 1000;
|
||||
var strokeOpacity = 0.8;
|
||||
var fillOpacity = 0.35;
|
||||
var callsign_service;
|
||||
|
|
@ -160,6 +158,7 @@ $(function(){
|
|||
marker.mode = update.mode;
|
||||
marker.band = update.band;
|
||||
marker.comment = update.location.comment;
|
||||
marker.ttl = update.location.ttl;
|
||||
|
||||
if (expectedCallsign && shallowEquals(expectedCallsign, update.source)) {
|
||||
map.panTo(pos);
|
||||
|
|
@ -200,6 +199,7 @@ $(function(){
|
|||
rectangle.mode = update.mode;
|
||||
rectangle.band = update.band;
|
||||
rectangle.center = center;
|
||||
rectangle.ttl = update.location.ttl;
|
||||
|
||||
rectangle.setOptions($.extend({
|
||||
strokeColor: color,
|
||||
|
|
@ -313,9 +313,6 @@ $(function(){
|
|||
title: config['receiver_name']
|
||||
});
|
||||
}
|
||||
if ('map_position_retention_time' in config) {
|
||||
retention_time = config.map_position_retention_time * 1000;
|
||||
}
|
||||
if ('callsign_service' in config) {
|
||||
callsign_service = config['callsign_service'];
|
||||
}
|
||||
|
|
@ -521,25 +518,25 @@ $(function(){
|
|||
infowindow.open(map, marker);
|
||||
};
|
||||
|
||||
var getScale = function(lastseen) {
|
||||
var getScale = function(lastseen, ttl) {
|
||||
var age = new Date().getTime() - lastseen;
|
||||
var scale = 1;
|
||||
if (age >= retention_time / 2) {
|
||||
scale = (retention_time - age) / (retention_time / 2);
|
||||
if (age >= ttl / 2) {
|
||||
scale = (ttl - age) / (ttl / 2);
|
||||
}
|
||||
return Math.max(0, Math.min(1, scale));
|
||||
};
|
||||
|
||||
var getRectangleOpacityOptions = function(lastseen) {
|
||||
var scale = getScale(lastseen);
|
||||
var getRectangleOpacityOptions = function(lastseen, ttl) {
|
||||
var scale = getScale(lastseen, ttl);
|
||||
return {
|
||||
strokeOpacity: strokeOpacity * scale,
|
||||
fillOpacity: fillOpacity * scale
|
||||
};
|
||||
};
|
||||
|
||||
var getMarkerOpacityOptions = function(lastseen) {
|
||||
var scale = getScale(lastseen);
|
||||
var getMarkerOpacityOptions = function(lastseen, ttl) {
|
||||
var scale = getScale(lastseen, ttl);
|
||||
return {
|
||||
opacity: scale
|
||||
};
|
||||
|
|
@ -550,21 +547,21 @@ $(function(){
|
|||
var now = new Date().getTime();
|
||||
Object.values(rectangles).forEach(function(m){
|
||||
var age = now - m.lastseen;
|
||||
if (age > retention_time) {
|
||||
if (age > m.ttl) {
|
||||
delete rectangles[sourceToKey(m.source)];
|
||||
m.setMap();
|
||||
return;
|
||||
}
|
||||
m.setOptions(getRectangleOpacityOptions(m.lastseen));
|
||||
m.setOptions(getRectangleOpacityOptions(m.lastseen, m.ttl));
|
||||
});
|
||||
Object.values(markers).forEach(function(m) {
|
||||
var age = now - m.lastseen;
|
||||
if (age > retention_time || (m.ttl && age > m.ttl)) {
|
||||
if (age > m.ttl) {
|
||||
delete markers[sourceToKey(m.source)];
|
||||
m.setMap();
|
||||
return;
|
||||
}
|
||||
m.setOptions(getMarkerOpacityOptions(m.lastseen));
|
||||
m.setOptions(getMarkerOpacityOptions(m.lastseen, m.ttl));
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
from csdr.module import PickleModule
|
||||
from math import sqrt, atan2, pi, floor, acos, cos
|
||||
from owrx.map import LatLngLocation, IncrementalUpdate, TTLUpdate, Location, Map
|
||||
from owrx.map import LatLngLocation, IncrementalUpdate, Location, Map
|
||||
from owrx.metrics import Metrics, CounterMetric
|
||||
from datetime import timedelta
|
||||
from datetime import datetime, timedelta
|
||||
from enum import Enum
|
||||
import time
|
||||
|
||||
FEET_PER_METER = 3.28084
|
||||
|
||||
|
||||
class AirplaneLocation(IncrementalUpdate, TTLUpdate, LatLngLocation):
|
||||
class AirplaneLocation(IncrementalUpdate, LatLngLocation):
|
||||
mapKeys = [
|
||||
"lat",
|
||||
"lon",
|
||||
|
|
@ -23,11 +22,10 @@ class AirplaneLocation(IncrementalUpdate, TTLUpdate, LatLngLocation):
|
|||
"IAS",
|
||||
"heading",
|
||||
]
|
||||
ttl = 30
|
||||
|
||||
def __init__(self, icao, message):
|
||||
self.history = []
|
||||
self.timestamp = time.time()
|
||||
self.timestamp = datetime.now()
|
||||
self.props = message
|
||||
self.icao = icao
|
||||
if "lat" in message and "lon" in message:
|
||||
|
|
@ -38,8 +36,8 @@ class AirplaneLocation(IncrementalUpdate, TTLUpdate, LatLngLocation):
|
|||
|
||||
def update(self, previousLocation: Location):
|
||||
history = previousLocation.history
|
||||
now = time.time()
|
||||
history = [p for p in history if now - p["timestamp"] < self.ttl]
|
||||
now = datetime.now()
|
||||
history = [p for p in history if now - p["timestamp"] < self.getTTL()]
|
||||
history += [{
|
||||
"timestamp": self.timestamp,
|
||||
"props": self.props,
|
||||
|
|
@ -62,8 +60,11 @@ class AirplaneLocation(IncrementalUpdate, TTLUpdate, LatLngLocation):
|
|||
dict["icao"] = self.icao
|
||||
return dict
|
||||
|
||||
|
||||
class AdsbLocation(AirplaneLocation):
|
||||
def getTTL(self) -> timedelta:
|
||||
return timedelta(seconds=self.ttl)
|
||||
# fixed ttl for adsb-locations for now
|
||||
return timedelta(seconds=30)
|
||||
|
||||
|
||||
class CprRecordType(Enum):
|
||||
|
|
@ -93,8 +94,8 @@ class CprCache:
|
|||
records = self.__getRecords(cprType)
|
||||
if icao not in records:
|
||||
return []
|
||||
now = time.time()
|
||||
filtered = [r for r in records[icao] if now - r["timestamp"] < 10]
|
||||
now = datetime.now()
|
||||
filtered = [r for r in records[icao] if now - r["timestamp"] < timedelta(seconds=10)]
|
||||
records_sorted = sorted(filtered, key=lambda r: r["timestamp"])
|
||||
records[icao] = records_sorted
|
||||
return [r["data"] for r in records_sorted]
|
||||
|
|
@ -103,7 +104,7 @@ class CprCache:
|
|||
records = self.__getRecords(cprType)
|
||||
if icao not in records:
|
||||
records[icao] = []
|
||||
records[icao].append({"timestamp": time.time(), "data": data})
|
||||
records[icao].append({"timestamp": datetime.now(), "data": data})
|
||||
|
||||
|
||||
class ModeSParser(PickleModule):
|
||||
|
|
@ -282,7 +283,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 = AirplaneLocation(message["icao"], data)
|
||||
loc = AdsbLocation(message["icao"], data)
|
||||
Map.getSharedInstance().updateLocation({"icao": message['icao']}, loc, "ADS-B", None)
|
||||
|
||||
return message
|
||||
|
|
|
|||
|
|
@ -458,7 +458,6 @@ class MapConnection(OpenWebRxClient):
|
|||
filtered_config = pm.filter(
|
||||
"google_maps_api_key",
|
||||
"receiver_gps",
|
||||
"map_position_retention_time",
|
||||
"callsign_service",
|
||||
"aircraft_tracking_service",
|
||||
"receiver_name",
|
||||
|
|
|
|||
|
|
@ -3,16 +3,12 @@ from pycsdr.types import Format
|
|||
from csdr.module import JsonParser
|
||||
from owrx.adsb.modes import AirplaneLocation
|
||||
from owrx.map import Map
|
||||
from datetime import timedelta
|
||||
|
||||
|
||||
class HfdlAirplaneLocation(AirplaneLocation):
|
||||
def __init__(self, message):
|
||||
super().__init__(None, message)
|
||||
|
||||
def getTTL(self) -> timedelta:
|
||||
return timedelta(minutes=60)
|
||||
|
||||
|
||||
class DumpHFDLModule(ExecModule):
|
||||
def __init__(self):
|
||||
|
|
|
|||
45
owrx/map.py
45
owrx/map.py
|
|
@ -12,8 +12,14 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
|
||||
class Location(object):
|
||||
def getTTL(self) -> timedelta:
|
||||
pm = Config.get()
|
||||
return timedelta(seconds=pm["map_position_retention_time"])
|
||||
|
||||
def __dict__(self):
|
||||
return {}
|
||||
return {
|
||||
"ttl": self.getTTL().total_seconds() * 1000
|
||||
}
|
||||
|
||||
|
||||
class Map(object):
|
||||
|
|
@ -120,21 +126,12 @@ class Map(object):
|
|||
# TODO broadcast removal to clients
|
||||
|
||||
def removeOldPositions(self):
|
||||
pm = Config.get()
|
||||
retention = timedelta(seconds=pm["map_position_retention_time"])
|
||||
now = datetime.now()
|
||||
cutoff = now - retention
|
||||
|
||||
def isExpired(pos):
|
||||
if pos["updated"] < cutoff:
|
||||
return True
|
||||
if isinstance(pos["location"], TTLUpdate):
|
||||
if now - pos["location"].getTTL() > pos["updated"]:
|
||||
return True
|
||||
return False
|
||||
|
||||
with self.positionsLock:
|
||||
to_be_removed = [key for (key, pos) in self.positions.items() if isExpired(pos)]
|
||||
to_be_removed = [
|
||||
key for (key, pos) in self.positions.items() if now - pos["location"].getTTL() > pos["updated"]
|
||||
]
|
||||
for key in to_be_removed:
|
||||
self.removeLocation(key)
|
||||
|
||||
|
|
@ -152,7 +149,10 @@ class LatLngLocation(Location):
|
|||
self.lon = lon
|
||||
|
||||
def __dict__(self):
|
||||
res = {"type": "latlon", "lat": self.lat, "lon": self.lon}
|
||||
res = super().__dict__()
|
||||
res.update(
|
||||
{"type": "latlon", "lat": self.lat, "lon": self.lon}
|
||||
)
|
||||
return res
|
||||
|
||||
|
||||
|
|
@ -161,21 +161,14 @@ class LocatorLocation(Location):
|
|||
self.locator = locator
|
||||
|
||||
def __dict__(self):
|
||||
return {"type": "locator", "locator": self.locator}
|
||||
res = super().__dict__()
|
||||
res.update(
|
||||
{"type": "locator", "locator": self.locator}
|
||||
)
|
||||
return res
|
||||
|
||||
|
||||
class IncrementalUpdate(Location, metaclass=ABCMeta):
|
||||
@abstractmethod
|
||||
def update(self, previousLocation: Location):
|
||||
pass
|
||||
|
||||
|
||||
class TTLUpdate(Location, metaclass=ABCMeta):
|
||||
@abstractmethod
|
||||
def getTTL(self) -> timedelta:
|
||||
pass
|
||||
|
||||
def __dict__(self):
|
||||
res = super().__dict__()
|
||||
res["ttl"] = self.getTTL().total_seconds() * 1000
|
||||
return res
|
||||
|
|
|
|||
Loading…
Reference in a new issue