apply ttl approach to all locations

This commit is contained in:
Jakob Ketterl 2023-09-06 15:18:04 +02:00
parent 22b6d3e645
commit 26896cf2d5
5 changed files with 46 additions and 60 deletions

View file

@ -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);

View file

@ -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

View file

@ -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",

View file

@ -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):

View file

@ -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