openwebrx-clone/owrx/reporting/wsprnet.py

98 lines
3.3 KiB
Python

from owrx.reporting.reporter import Reporter
from owrx.version import openwebrx_version
from owrx.config import Config
from owrx.locator import Locator
from owrx.metrics import Metrics, CounterMetric
from queue import Queue, Full
from urllib import request, parse
import threading
import logging
from datetime import datetime, timezone
logger = logging.getLogger(__name__)
PoisonPill = object()
class Worker(threading.Thread):
def __init__(self, queue: Queue):
self.queue = queue
self.doRun = True
super().__init__(daemon=True)
def run(self):
while self.doRun:
try:
spot = self.queue.get()
if spot is PoisonPill:
self.doRun = False
else:
self.uploadSpot(spot)
self.queue.task_done()
except Exception:
logger.exception("Exception while uploading WSPRNet spot")
def _getMode(self, spot):
interval = round(spot["interval"] / 60)
# FST4W modes are mapped not to conflict with WSPR modes 2 and 15:
if spot["mode"] != "WSPR" and interval in [2, 15]:
return interval + 1
return interval
def uploadSpot(self, spot):
config = Config.get()
# function=wspr&date=210114&time=1732&sig=-15&dt=0.5&drift=0&tqrg=7.040019&tcall=DF2UU&tgrid=JN48&dbm=37&version=2.3.0-rc3&rcall=DD5JFK&rgrid=JN58SC&rqrg=7.040047&mode=2
# {'timestamp': 1610655960000, 'db': -23.0, 'dt': 0.3, 'freq': 7040048, 'drift': -1, 'msg': 'LA3JJ JO59 37', 'callsign': 'LA3JJ', 'locator': 'JO59', 'mode': 'WSPR'}
date = datetime.fromtimestamp(spot["timestamp"] / 1000, tz=timezone.utc)
data = parse.urlencode(
{
"function": "wspr",
"date": date.strftime("%y%m%d"),
"time": date.strftime("%H%M"),
"sig": spot["db"],
"dt": spot["dt"],
# FST4W does not have drift
"drift": spot["drift"] if "drift" in spot else 0,
"tqrg": spot["freq"] / 1e6,
"tcall": spot["callsign"],
"tgrid": spot["locator"],
"dbm": spot["dbm"],
"version": openwebrx_version,
"rcall": config["wsprnet_callsign"],
"rgrid": Locator.fromCoordinates(config["receiver_gps"]),
"mode": self._getMode(spot),
}
).encode()
request.urlopen("http://wsprnet.org/post/", data, timeout=60)
class WsprnetReporter(Reporter):
def __init__(self):
# max 100 entries
self.queue = Queue(100)
# single worker
Worker(self.queue).start()
# metrics
metrics = Metrics.getSharedInstance()
self.spotCounter = CounterMetric()
metrics.addMetric("wsprnet.spots", self.spotCounter)
def stop(self):
while not self.queue.empty():
self.queue.get(timeout=1)
self.queue.task_done()
self.queue.put(PoisonPill)
def spot(self, spot):
try:
self.queue.put(spot, block=False)
self.spotCounter.inc()
except Full:
logger.warning("WSPRNet Queue overflow, one spot lost")
def getSupportedModes(self):
return ["WSPR", "FST4W"]