Placing EIBI stations on the map, with the current frequencies.

This commit is contained in:
Marat Fayzullin 2023-07-16 21:18:58 -04:00
parent 021e1b5f1d
commit 2b23ddfb31
3 changed files with 106 additions and 31 deletions

View File

@ -214,6 +214,7 @@ $(function(){
marker.altitude = update.location.altitude;
marker.device = update.location.device;
marker.antenna = update.location.antenna;
marker.schedule = update.location.schedule;
if (expectedCallsign && expectedCallsign == update.callsign) {
map.panTo(pos);
@ -457,7 +458,7 @@ $(function(){
return '<a target="callsign_info" href="' +
url.replaceAll('{}', callsign.replace(new RegExp('-.*$'), '')) +
'">' + callsign + '</a>';
};
}
var distanceKm = function(p1, p2) {
// Earth radius in km
@ -521,7 +522,8 @@ $(function(){
var makeListItem = function(name, value) {
return '<div style="border-bottom:1px dotted;">'
+ '<span>' + name + '</span>'
+ '<span>' + name.replace(/[ \r\n]+/gm, '&nbsp;')
+ '</span>&nbsp;&nbsp;&nbsp;&nbsp;'
+ '<span style="float:right;">' + value + '</span>'
+ '</div>';
}
@ -664,6 +666,7 @@ $(function(){
var marker = markers[name];
var commentString = "";
var detailsString = "";
var scheduleString = "";
var nameString = "";
var distance = "";
@ -692,17 +695,32 @@ $(function(){
detailsString += makeListItem('Antenna', truncate(marker.antenna, 24));
}
if (marker.schedule) {
for (var j=0 ; j<marker.schedule.length ; ++j) {
var freq = marker.schedule[j].freq;
var mode = marker.schedule[j].mode;
freq = '<a target="owrx_receiver" href="/#freq=' + freq
+ ',mod=' + (mode? mode : 'am') + '">'
+ Math.round(marker.schedule[j].freq/1000) + 'kHz</a>';
scheduleString += makeListItem(marker.schedule[j].name, freq);
}
}
if (detailsString.length > 0) {
detailsString = '<p>' + makeListTitle('Details') + detailsString + '</p>';
}
if (scheduleString.length > 0) {
scheduleString = '<p>' + makeListTitle('Schedule') + scheduleString + '</p>';
}
if (receiverMarker) {
distance = " at " + distanceKm(receiverMarker.position, marker.position) + " km";
}
infowindow.setContent(
'<h3>' + nameString + distance + '</h3>' +
commentString + detailsString
commentString + detailsString + scheduleString
);
infowindow.open(map, marker);

View File

@ -46,6 +46,7 @@ class EIBI(object):
def __init__(self):
self.refreshPeriod = 60*60*24*30
self.event = threading.Event()
self.lock = threading.Lock()
self.schedule = []
self.thread = None
@ -74,11 +75,11 @@ class EIBI(object):
ts = os.path.getmtime(file) if os.path.isfile(file) else 0
# Try loading cached schedule from file first, unless stale
if time.time() - ts < self.refreshPeriod:
logger.debug("Loading cached schedule from '{0}'...".format(file))
self.schedule = self.loadSchedule(file)
else:
self.schedule = self.updateSchedule()
with self.lock:
if time.time() - ts < self.refreshPeriod:
self.schedule = self.loadSchedule(file)
else:
self.schedule = self.updateSchedule()
while not self.event.is_set():
# Sleep until it is time to update schedule
@ -87,22 +88,25 @@ class EIBI(object):
if not self.event.is_set():
# Update schedule
logger.debug("Refreshing schedule...")
self.schedule = self.updateSchedule()
with self.lock:
self.schedule = self.updateSchedule()
# Done
logger.debug("Stopped EIBI main thread.")
self.thread = None
# Load schedule from a given JSON file
def loadSchedule(self, fileName: str):
def loadSchedule(self, file: str):
logger.debug("Loading schedule from '{0}'...".format(file))
try:
with open(fileName, "r") as f:
with open(file, "r") as f:
result = json.load(f)
f.close()
except Exception as e:
logger.debug("loadSchedule() exception: {0}".format(e))
result = []
# Done
logger.debug("Loaded {0} entries from '{1}'...".format(len(result), file))
return result
# Update schedule
@ -122,33 +126,66 @@ class EIBI(object):
# Done
return schedule
# Find all current broadcasts for a given source
def findBySource(self, src: str):
# Get entries active at the current time
now = datetime.utcnow()
now = now.hour * 100 + now.minute
result = []
# Search for entries originating from given source at current time
for entry in self.schedule:
if entry["time1"] <= now and entry["time2"] > now:
if entry["itu"] + entry["src"] == src:
result.append(entry)
with self.lock:
for entry in self.schedule:
if entry["time1"] <= now and entry["time2"] > now:
if entry["itu"] + entry["src"] == src:
result.append(entry)
# Done
return result
# Find all current broadcasts for a given frequency range
def findCurrent(self, freq1: int, freq2: int):
# Get entries active at the current time
now = datetime.utcnow()
now = now.hour * 100 + now.minute
return self.find(freq1, freq2, now, now)
# Find all broadcasts for given frequency and time ranges
def find(self, freq1: int, freq2: int, time1: int, time2: int):
result = []
# Search for entries within given frequency and time ranges
for entry in self.schedule:
f = entry["freq"]
if f >= freq1 and f <= freq2:
if entry["time1"] <= time2 and entry["time2"] > time1:
result.append(entry)
with self.lock:
for entry in self.schedule:
f = entry["freq"]
if f >= freq1 and f <= freq2:
if entry["time1"] <= time2 and entry["time2"] > time1:
result.append(entry)
# Done
return result
# Create list of currently broadcasting locations
def currentTransmitters(self):
# Get entries active at the current time
now = datetime.utcnow()
day = str(now.weekday() + 1)
now = now.hour * 100 + now.minute
result = {}
# Search for current entries
with self.lock:
for entry in self.schedule:
# For every current schedule entry...
if entry["time1"] <= now and entry["time2"] > now and day in entry["days"]:
src = entry["itu"] + entry["src"]
# Find all matching transmitter locations
for loc in EIBI_Locations:
if loc["code"] == src:
# Add location to the result
name = loc["name"]
logger.debug("Found {0} .. {1} .. {2} from {3} ({4})".format(
entry["time1"], now, entry["time2"], name, src))
if name not in result:
result[name] = loc.copy()
result[name]["schedule"] = []
# Add schedule entry to the location
result[name]["schedule"].append(entry)
# Done
return result
@ -197,8 +234,25 @@ class EIBI(object):
# When we encounter a location...
m = pattern.match(line)
if m is not None:
# Guess modulation by language and name fields
name = m.group(6).lower()
lang = m.group(7)
mode = (
"hfdl" if lang == "-HF" else
"rtty450" if lang == "-TY" else
"cw" if lang == "-CW" else
"fax" if " fax" in name else
"usb" if "volmet" in name else
"usb" if "ldoc" in name else
"usb" if "car-" in name else
"usb" if "nat-" in name else
"usb" if " usb" in name else
"usb" if "fsk" in name else
"am")
# Append a new entry to the result
result.append({
"freq" : int(float(m.group(1)) * 1000),
"mode" : mode,
"time1" : int(m.group(2)),
"time2" : int(m.group(3)),
"days" : self.convertDays(m.group(4)),

View File

@ -2,7 +2,7 @@ from owrx.config.core import CoreConfig
from owrx.map import Map, Location
from owrx.aprs import getSymbolData
from json import JSONEncoder
from owrx.eibi import EIBI_Locations
from owrx.eibi import EIBI_Locations, EIBI
import urllib
import threading
@ -107,25 +107,23 @@ class Markers(object):
# Load markers from local files
for file in self.fileList:
if os.path.isfile(file):
logger.debug("Loading markers from '{0}'...".format(file))
self.markers.update(self.loadMarkers(file))
# Load markers from the EIBI database
#logger.debug("Loading EIBI transmitter locations...")
#self.markers.update(self.loadEIBI())
# This file contains cached database
file = self._getCachedMarkersFile()
ts = os.path.getmtime(file) if os.path.isfile(file) else 0
# Try loading cached database from file first, unless stale
if time.time() - ts < self.refreshPeriod:
logger.debug("Loading cached markers from '{0}'...".format(file))
self.markers.update(self.loadMarkers(file))
else:
# Add scraped data to the database
self.markers.update(self.updateCache())
# Load markers from the EIBI database
time.sleep(30)
self.markers.update(self.loadEIBI())
while not self.event.is_set():
# Update map with markers
logger.debug("Updating map...")
@ -143,10 +141,11 @@ class Markers(object):
self.thread = None
# Load markers from a given file
def loadMarkers(self, fileName: str):
def loadMarkers(self, file: str):
logger.debug("Loading markers from '{0}'...".format(file))
# Load markers list from JSON file
try:
with open(fileName, "r") as f:
with open(file, "r") as f:
db = json.load(f)
f.close()
except Exception as e:
@ -160,6 +159,7 @@ class Markers(object):
result[key] = MarkerLocation(attrs)
# Done
logger.debug("Loaded {0} markers from '{1}'.".format(len(result), file))
return result
# Update markers on the map
@ -194,11 +194,12 @@ class Markers(object):
#
def loadEIBI(self):
logger.debug("Loading EIBI transmitter locations...")
#url = "https://www.short-wave.info/index.php?txsite="
url = "https://www.google.com/search?q="
result = {}
# Load transmitter sites from EIBI database
for entry in EIBI_Locations:
for entry in EIBI.getSharedInstance().currentTransmitters().values():
rl = MarkerLocation({
"type" : "feature",
"mode" : "Stations",
@ -206,10 +207,12 @@ class Markers(object):
"id" : entry["name"],
"lat" : entry["lat"],
"lon" : entry["lon"],
"url" : url + urllib.parse.quote_plus(entry["name"])
"url" : url + urllib.parse.quote_plus(entry["name"]),
"schedule": entry["schedule"]
})
result[rl.getId()] = rl
# Done
logger.debug("Loaded {0} EIBI transmitter locations.".format(len(result)))
return result
def scrapeOWRX(self, url: str = "https://www.receiverbook.de/map"):