From 2ccfa2811988bf70a974bd51411575d36d1e9cce Mon Sep 17 00:00:00 2001 From: Ian Renton Date: Sun, 2 Nov 2025 20:51:16 +0000 Subject: [PATCH] Get "qth" friendly name from QRZ/clublog and return in the callsign lookup. Closes #77 --- core/lookup_helper.py | 17 ++++++++++++++--- data/alert.py | 2 +- data/spot.py | 22 +++++++++++++++++----- server/webserver.py | 1 + webassets/apidocs/openapi.yml | 8 ++++++++ 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/core/lookup_helper.py b/core/lookup_helper.py index 57a3d71..faf9cd4 100644 --- a/core/lookup_helper.py +++ b/core/lookup_helper.py @@ -301,7 +301,7 @@ class LookupHelper: return ituz # Infer an operator name from a callsign (requires QRZ.com/HamQTH) - def infer_name_from_callsign(self, call): + def infer_name_from_callsign_online_lookup(self, call): data = self.get_qrz_data_for_callsign(call) if data and "fname" in data: name = data["fname"] @@ -315,7 +315,7 @@ class LookupHelper: return None # Infer a latitude and longitude from a callsign (requires QRZ.com/HamQTH) - def infer_latlon_from_callsign_qrz(self, call): + def infer_latlon_from_callsign_online_lookup(self, call): data = self.get_qrz_data_for_callsign(call) if data and "latitude" in data and "longitude" in data: return [data["latitude"], data["longitude"]] @@ -326,7 +326,7 @@ class LookupHelper: return None # Infer a grid locator from a callsign (requires QRZ.com/HamQTH) - def infer_grid_from_callsign_qrz(self, call): + def infer_grid_from_callsign_online_lookup(self, call): data = self.get_qrz_data_for_callsign(call) if data and "locator" in data: return data["locator"] @@ -336,6 +336,17 @@ class LookupHelper: else: return None + # Infer a textual QTH from a callsign (requires QRZ.com/HamQTH) + def infer_qth_from_callsign_online_lookup(self, call): + data = self.get_qrz_data_for_callsign(call) + if data and "addr2" in data: + return data["addr2"] + data = self.get_hamqth_data_for_callsign(call) + if data and "qth" in data: + return data["qth"] + else: + return None + # Infer a latitude and longitude from a callsign (using DXCC, probably very inaccurate) def infer_latlon_from_callsign_dxcc(self, call): try: diff --git a/data/alert.py b/data/alert.py index 3709af4..ae04333 100644 --- a/data/alert.py +++ b/data/alert.py @@ -121,7 +121,7 @@ class Alert: # the actual alertting service, e.g. we don't want to accidentally use a user's QRZ.com home lat/lon instead of # the one from the park reference they're at. if self.dx_calls and not self.dx_names: - self.dx_names = list(map(lambda c: lookup_helper.infer_name_from_callsign(c), self.dx_calls)) + self.dx_names = list(map(lambda c: lookup_helper.infer_name_from_callsign_online_lookup(c), self.dx_calls)) # Always create an ID based on a hash of every parameter *except* received_time. This is used as the index # to a map, which as a byproduct avoids us having multiple duplicate copies of the object that are identical diff --git a/data/spot.py b/data/spot.py index 71a69f1..6a79402 100644 --- a/data/spot.py +++ b/data/spot.py @@ -27,6 +27,9 @@ class Spot: dx_call: str = None # Name of the operator that has been spotted dx_name: str = None + # QTH of the operator that has been spotted. This could be from any SIG refs or could be from online lookup of their + # home QTH. + dx_qth: str = None # Country of the DX operator dx_country: str = None # Country flag of the DX operator @@ -313,15 +316,24 @@ class Spot: # the actual spotting service, e.g. we don't want to accidentally use a user's QRZ.com home lat/lon instead of # the one from the park reference they're at. if self.dx_call and not self.dx_name: - self.dx_name = lookup_helper.infer_name_from_callsign(self.dx_call) + self.dx_name = lookup_helper.infer_name_from_callsign_online_lookup(self.dx_call) if self.dx_call and not self.dx_latitude: - latlon = lookup_helper.infer_latlon_from_callsign_qrz(self.dx_call) + latlon = lookup_helper.infer_latlon_from_callsign_online_lookup(self.dx_call) if latlon: self.dx_latitude = latlon[0] self.dx_longitude = latlon[1] - self.dx_grid = lookup_helper.infer_grid_from_callsign_qrz(self.dx_call) + self.dx_grid = lookup_helper.infer_grid_from_callsign_online_lookup(self.dx_call) self.dx_location_source = "HOME QTH" + # Determine a "QTH" string. If we have a SIG ref, pick the first one and turn it into a suitable stirng, + # otherwise see what they have set on an online lookup service. + if self.sig_refs and len(self.sig_refs) > 0: + self.dx_qth = self.sig_refs[0].id + if self.sig_refs[0].name: + self.dx_qth = self.dx_qth + " " + self.sig_refs[0].name + else: + self.dx_qth = lookup_helper.infer_qth_from_callsign_online_lookup(self.dx_call) + # Last resort for getting a DX position, use the DXCC entity. if self.dx_call and not self.dx_latitude: latlon = lookup_helper.infer_latlon_from_callsign_dxcc(self.dx_call) @@ -341,11 +353,11 @@ class Spot: if self.de_call and any(char.isdigit() for char in self.de_call) and not (self.de_call.startswith("T2") and self.source == "APRS-IS"): # DE operator position lookup, using QRZ.com. if not self.de_latitude: - latlon = lookup_helper.infer_latlon_from_callsign_qrz(self.de_call) + latlon = lookup_helper.infer_latlon_from_callsign_online_lookup(self.de_call) if latlon: self.de_latitude = latlon[0] self.de_longitude = latlon[1] - self.de_grid = lookup_helper.infer_grid_from_callsign_qrz(self.de_call) + self.de_grid = lookup_helper.infer_grid_from_callsign_online_lookup(self.de_call) # Last resort for getting a DE position, use the DXCC entity. if not self.de_latitude: diff --git a/server/webserver.py b/server/webserver.py index 9041a63..a95b424 100644 --- a/server/webserver.py +++ b/server/webserver.py @@ -127,6 +127,7 @@ class WebServer: return self.serve_api({ "call": call, "name": fake_spot.dx_name, + "qth": fake_spot.dx_qth, "country": fake_spot.dx_country, "flag": fake_spot.dx_flag, "continent": fake_spot.dx_continent, diff --git a/webassets/apidocs/openapi.yml b/webassets/apidocs/openapi.yml index 26d7065..1855886 100644 --- a/webassets/apidocs/openapi.yml +++ b/webassets/apidocs/openapi.yml @@ -518,6 +518,10 @@ paths: type: string description: Name of the operator example: Ian + qth: + type: string + description: QTH of the operator. This could be from any SIG refs or could be from online lookup of their home QTH. + example: Dorset country: type: string description: Country of the operator @@ -745,6 +749,10 @@ components: type: string description: Name of the operator that has been spotted example: Ian + dx_qth: + type: string + description: QTH of the operator that has been spotted. This could be from any SIG refs or could be from online lookup of their home QTH. + example: Dorset dx_country: type: string description: Country of the DX operator