Refactor looking up SIG reference details into a common location, taking it out of the individual spot providers. This means we can now look up references properly from Cluster spot comments, etc. Closes #74 as there is no longer any duplication of these lookups. Works towards #54 as sig_refs now specify their sig internally.

This commit is contained in:
Ian Renton
2025-11-02 15:45:19 +00:00
parent 28010a68ae
commit 286ff66721
22 changed files with 192 additions and 233 deletions

View File

@@ -99,6 +99,11 @@ class Alert:
if self.dx_dxcc_id and self.dx_dxcc_id in DXCC_FLAGS and not self.dx_flag:
self.dx_flag = DXCC_FLAGS[self.dx_dxcc_id]
# If the spot itself doesn't have a SIG yet, but we have at least one SIG reference, take that reference's SIG
# and apply it to the whole spot.
if self.sig_refs and len(self.sig_refs) > 0 and not self.sig:
self.sig = self.sig_refs[0].sig
# Icon from SIG
if self.sig and not self.icon:
self.icon = get_icon_for_sig(self.sig)

View File

@@ -6,7 +6,15 @@ from dataclasses import dataclass
class SIGRef:
# Reference ID, e.g. "GB-0001".
id: str
# SIG that this reference is in, e.g. "POTA".
sig: str
# Name of the reference, e.g. "Null Country Park", if known.
name: str = None
# URL to look up more information about the reference, if known.
url: str = None
url: str = None
# Latitude of the reference, if known.
latitude: float = None
# Longitude of the reference, if known.
longitude: float = None
# Maidenhead grid reference of the reference, if known.
grid: str = None

View File

@@ -10,9 +10,8 @@ import pytz
from pyhamtools.locator import locator_to_latlong, latlong_to_locator
from core.constants import DXCC_FLAGS
from core.geo_utils import wab_wai_square_to_lat_lon
from core.lookup_helper import lookup_helper
from core.sig_utils import get_icon_for_sig
from core.sig_utils import get_icon_for_sig, get_sig_ref_info
# Data class that defines a spot.
@@ -232,11 +231,40 @@ class Spot:
if self.mode and not self.mode_type:
self.mode_type = lookup_helper.infer_mode_type_from_mode(self.mode)
# If we have a latitude at this point, it can only have been provided by the spot itself
if self.dx_latitude:
self.dx_location_source = "SPOT"
# Fetch SIG data. In case a particular API doesn't provide a full set of name, lat, lon & grid for a reference
# in its initial call, we use this code to populate the rest of the data. This includes working out grid refs
# from WAB and WAI, which count as a SIG even though there's no real lookup, just maths
if self.sig_refs and len(self.sig_refs) > 0:
for sig_ref in self.sig_refs:
lookup_data = get_sig_ref_info(sig_ref.sig, sig_ref.id)
if lookup_data:
# Update the sig_ref data from the lookup
sig_ref.__dict__.update(lookup_data.__dict__)
# If the spot itself doesn't have location yet, but the SIG ref does, extract it
if lookup_data.grid and not self.dx_grid:
self.dx_grid = lookup_data.grid
if lookup_data.latitude and not self.dx_latitude:
self.dx_latitude = lookup_data.latitude
self.dx_longitude = lookup_data.longitude
if self.sig == "WAB" or self.sig == "WAI":
self.dx_location_source = "WAB/WAI GRID"
else:
self.dx_location_source = "SIG REF LOOKUP"
# If the spot itself doesn't have a SIG yet, but we have at least one SIG reference, take that reference's SIG
# and apply it to the whole spot.
if self.sig_refs and len(self.sig_refs) > 0 and not self.sig:
self.sig = self.sig_refs[0].sig
# Icon from SIG
if self.sig and not self.icon:
self.icon = get_icon_for_sig(self.sig)
# DX Grid to lat/lon and vice versa
# DX Grid to lat/lon and vice versa in case one is missing
if self.dx_grid and not self.dx_latitude:
ll = locator_to_latlong(self.dx_grid)
self.dx_latitude = ll[0]
@@ -246,21 +274,6 @@ class Spot:
self.dx_grid = latlong_to_locator(self.dx_latitude, self.dx_longitude, 8)
except:
logging.debug("Invalid lat/lon received for spot")
if self.dx_latitude:
self.dx_location_source = "SPOT"
# WAB/WAI grid to lat/lon
if not self.dx_latitude and self.sig and self.sig_refs and len(self.sig_refs) > 0 and (
self.sig == "WAB" or self.sig == "WAI"):
ll = wab_wai_square_to_lat_lon(self.sig_refs[0])
if ll:
self.dx_latitude = ll[0]
self.dx_longitude = ll[1]
try:
self.dx_grid = latlong_to_locator(self.dx_latitude, self.dx_longitude, 8)
except:
logging.debug("Invalid lat/lon received from WAB/WAI grid")
self.dx_location_source = "WAB/WAI GRID"
# QRT comment detection
if self.comment and not self.qrt:
@@ -290,8 +303,9 @@ class Spot:
# DX Location is "good" if it is from a spot, or from QRZ if the callsign doesn't contain a slash, so the operator
# is likely at home.
self.dx_location_good = self.dx_location_source == "SPOT" or self.dx_location_source == "WAB/WAI GRID" or (
self.dx_location_source == "QRZ" and not "/" in self.dx_call)
self.dx_location_good = (self.dx_location_source == "SPOT" or self.dx_location_source == "SIG REF LOOKUP"
or self.dx_location_source == "WAB/WAI GRID"
or (self.dx_location_source == "QRZ" and not "/" in self.dx_call))
# DE with no digits and APRS servers starting "T2" are not things we can look up location for
if any(char.isdigit() for char in self.de_call) and not (self.de_call.startswith("T2") and self.source == "APRS-IS"):