mirror of
https://git.ianrenton.com/ian/spothole.git
synced 2025-10-27 08:49:27 +00:00
Add "de_" variants of grid/lat/lon #42
This commit is contained in:
@@ -159,7 +159,7 @@ DXCC_FLAGS = {
|
|||||||
107: "\U0001F1EC\U0001F1F3", # GUINEA
|
107: "\U0001F1EC\U0001F1F3", # GUINEA
|
||||||
108: "\U0001F1E7\U0001F1F7", # BRAZIL
|
108: "\U0001F1E7\U0001F1F7", # BRAZIL
|
||||||
109: "\U0001F1EC\U0001F1FC", # GUINEA-BISSAU
|
109: "\U0001F1EC\U0001F1FC", # GUINEA-BISSAU
|
||||||
110: "", # HAWAII
|
110: "\U0001F1FA\U0001F1F8", # HAWAII
|
||||||
111: "\U0001F1ED\U0001F1F2", # HEARD ISLAND
|
111: "\U0001F1ED\U0001F1F2", # HEARD ISLAND
|
||||||
112: "\U0001F1E8\U0001F1F1", # CHILE
|
112: "\U0001F1E8\U0001F1F1", # CHILE
|
||||||
113: "", # IFNI
|
113: "", # IFNI
|
||||||
|
|||||||
179
data/spot.py
179
data/spot.py
@@ -10,29 +10,26 @@ from pyhamtools.locator import locator_to_latlong, latlong_to_locator
|
|||||||
from core.constants import DXCC_FLAGS
|
from core.constants import DXCC_FLAGS
|
||||||
from core.lookup_helper import lookup_helper
|
from core.lookup_helper import lookup_helper
|
||||||
|
|
||||||
|
|
||||||
# Data class that defines a spot.
|
# Data class that defines a spot.
|
||||||
@dataclass
|
@dataclass
|
||||||
class Spot:
|
class Spot:
|
||||||
# Unique identifier for the spot
|
# Unique identifier for the spot
|
||||||
id: str = None
|
id: str = None
|
||||||
|
|
||||||
|
|
||||||
|
# DX (spotted) operator info
|
||||||
|
|
||||||
# Callsign of the operator that has been spotted
|
# Callsign of the operator that has been spotted
|
||||||
dx_call: str = None
|
dx_call: str = None
|
||||||
# Callsign of the operator that has spotted them
|
|
||||||
de_call: str = None
|
|
||||||
# Name of the operator that has been spotted
|
# Name of the operator that has been spotted
|
||||||
dx_name: str = None
|
dx_name: str = None
|
||||||
# Country of the DX operator
|
# Country of the DX operator
|
||||||
dx_country: str = None
|
dx_country: str = None
|
||||||
# Country of the spotter
|
|
||||||
de_country: str = None
|
|
||||||
# Country flag of the DX operator
|
# Country flag of the DX operator
|
||||||
dx_flag: str = None
|
dx_flag: str = None
|
||||||
# Country flag of the spotter
|
|
||||||
de_flag: str = None
|
|
||||||
# Continent of the DX operator
|
# Continent of the DX operator
|
||||||
dx_continent: str = None
|
dx_continent: str = None
|
||||||
# Continent of the spotter
|
|
||||||
de_continent: str = None
|
|
||||||
# DXCC ID of the DX operator
|
# DXCC ID of the DX operator
|
||||||
dx_dxcc_id: int = None
|
dx_dxcc_id: int = None
|
||||||
# DXCC ID of the spotter
|
# DXCC ID of the spotter
|
||||||
@@ -44,6 +41,42 @@ class Spot:
|
|||||||
# If this is an APRS spot, what SSID was the DX operator using?
|
# If this is an APRS spot, what SSID was the DX operator using?
|
||||||
# This is a string not an int for now, as I often see non-numeric ones somehow
|
# This is a string not an int for now, as I often see non-numeric ones somehow
|
||||||
dx_aprs_ssid: str = None
|
dx_aprs_ssid: str = None
|
||||||
|
# Maidenhead grid locator for the DX. This could be from a geographical reference e.g. POTA, or just from the
|
||||||
|
# country
|
||||||
|
dx_grid: str = None
|
||||||
|
# Latitude & longitude of the DX, in degrees. This could be from a geographical reference e.g. POTA, or from a QRZ
|
||||||
|
# lookup
|
||||||
|
dx_latitude: float = None
|
||||||
|
dx_longitude: float = None
|
||||||
|
# DX Location source. Indicates how accurate the location might be. Values: "SPOT", "QRZ, "DXCC", "NONE"
|
||||||
|
dx_location_source: str = "NONE"
|
||||||
|
# DX Location good. Indicates that the software thinks the location data is good enough to plot on a map.
|
||||||
|
dx_location_good: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
# DE (Spotter) info
|
||||||
|
|
||||||
|
# Callsign of the spotter
|
||||||
|
de_call: str = None
|
||||||
|
# Country of the spotter
|
||||||
|
de_country: str = None
|
||||||
|
# Country flag of the spotter
|
||||||
|
de_flag: str = None
|
||||||
|
# Continent of the spotter
|
||||||
|
de_continent: str = None
|
||||||
|
# Maidenhead grid locator for the spotter. This is not going to be from a xOTA reference so it will likely just be
|
||||||
|
# a QRZ or DXCC lookup. If the spotter is also portable, this is probably wrong, but it's good enough for some
|
||||||
|
# simple mapping.
|
||||||
|
de_grid: str = None
|
||||||
|
# Latitude & longitude of the DX, in degrees. This is not going to be from a xOTA reference so it will likely just
|
||||||
|
# be a QRZ or DXCC lookup. If the spotter is also portable, this is probably wrong, but it's good enough for some
|
||||||
|
# simple mapping.
|
||||||
|
de_latitude: float = None
|
||||||
|
de_longitude: float = None
|
||||||
|
|
||||||
|
|
||||||
|
# General QSO info
|
||||||
|
|
||||||
# Reported mode, such as SSB, PHONE, CW, FT8...
|
# Reported mode, such as SSB, PHONE, CW, FT8...
|
||||||
mode: str = None
|
mode: str = None
|
||||||
# Inferred mode "family". One of "CW", "PHONE" or "DIGI".
|
# Inferred mode "family". One of "CW", "PHONE" or "DIGI".
|
||||||
@@ -54,18 +87,14 @@ class Spot:
|
|||||||
freq: float = None
|
freq: float = None
|
||||||
# Band, defined by the frequency, e.g. "40m" or "70cm"
|
# Band, defined by the frequency, e.g. "40m" or "70cm"
|
||||||
band: str = None
|
band: str = None
|
||||||
# Time of the spot, UTC seconds since UNIX epoch
|
|
||||||
time: float = None
|
|
||||||
# Time of the spot, ISO 8601
|
|
||||||
time_iso: str = None
|
|
||||||
# Time that this software received the spot, UTC seconds since UNIX epoch. This is used with the "since_received"
|
|
||||||
# call to our API to receive all data that is new to us, even if by a quirk of the API it might be older than the
|
|
||||||
# list time the client polled the API.
|
|
||||||
received_time: float = None
|
|
||||||
# Time that this software received the spot, ISO 8601
|
|
||||||
received_time_iso: str = None
|
|
||||||
# Comment left by the spotter, if any
|
# Comment left by the spotter, if any
|
||||||
comment: str = None
|
comment: str = None
|
||||||
|
# QRT state. Some APIs return spots marked as QRT. Otherwise we can check the comments.
|
||||||
|
qrt: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
# Special Interest Group info
|
||||||
|
|
||||||
# Special Interest Group (SIG), e.g. outdoor activity programme such as POTA
|
# Special Interest Group (SIG), e.g. outdoor activity programme such as POTA
|
||||||
sig: str = None
|
sig: str = None
|
||||||
# SIG references. We allow multiple here for e.g. n-fer activations, unlike ADIF SIG_INFO
|
# SIG references. We allow multiple here for e.g. n-fer activations, unlike ADIF SIG_INFO
|
||||||
@@ -76,17 +105,24 @@ class Spot:
|
|||||||
activation_score: int = None
|
activation_score: int = None
|
||||||
# Icon, from the Font Awesome set. This is fairly opinionated but is here to help the Spothole web UI and Field Spotter. Does not include the "fa-" prefix.
|
# Icon, from the Font Awesome set. This is fairly opinionated but is here to help the Spothole web UI and Field Spotter. Does not include the "fa-" prefix.
|
||||||
icon: str = "question"
|
icon: str = "question"
|
||||||
# Maidenhead grid locator for the spot. This could be from a geographical reference e.g. POTA, or just from the country
|
|
||||||
grid: str = None
|
|
||||||
# Latitude & longitude, in degrees. This could be from a geographical reference e.g. POTA, or from a QRZ lookup
|
# Timing info
|
||||||
latitude: float = None
|
|
||||||
longitude: float = None
|
# Time of the spot, UTC seconds since UNIX epoch
|
||||||
# Location source. Indicates how accurate the location might be. Values: "SPOT", "QRZ, "DXCC", "NONE"
|
time: float = None
|
||||||
location_source: str = "NONE"
|
# Time of the spot, ISO 8601
|
||||||
# Location good. Indicates that the software thinks the location data is good enough to plot on a map.
|
time_iso: str = None
|
||||||
location_good: bool = False
|
# Time that this software received the spot, UTC seconds since UNIX epoch. This is used with the "since_received"
|
||||||
# QRT state. Some APIs return spots marked as QRT. Otherwise we can check the comments.
|
# call to our API to receive all data that is new to us, even if by a quirk of the API it might be older than the
|
||||||
qrt: bool = False
|
# list time the client polled the API.
|
||||||
|
received_time: float = None
|
||||||
|
# Time that this software received the spot, ISO 8601
|
||||||
|
received_time_iso: str = None
|
||||||
|
|
||||||
|
|
||||||
|
# Source info
|
||||||
|
|
||||||
# Where we got the spot from, e.g. "POTA", "Cluster"...
|
# Where we got the spot from, e.g. "POTA", "Cluster"...
|
||||||
source: str = None
|
source: str = None
|
||||||
# The ID the source gave it, if any.
|
# The ID the source gave it, if any.
|
||||||
@@ -131,15 +167,17 @@ class Spot:
|
|||||||
if self.de_call and "-" in self.de_call:
|
if self.de_call and "-" in self.de_call:
|
||||||
self.de_call = self.de_call.split("-")[0]
|
self.de_call = self.de_call.split("-")[0]
|
||||||
|
|
||||||
# Spotter country, continent, zones etc. from callsign
|
# Spotter country, continent, zones etc. from callsign.
|
||||||
if self.de_call and not self.de_country:
|
# DE of "RBNHOLE" and "SOTAMAT" are not things we can look up location for
|
||||||
self.de_country = lookup_helper.infer_country_from_callsign(self.de_call)
|
if self.de_call != "RBNHOLE" and self.de_call != "SOTAMAT":
|
||||||
if self.de_call and not self.de_continent:
|
if self.de_call and not self.de_country:
|
||||||
self.de_continent = lookup_helper.infer_continent_from_callsign(self.de_call)
|
self.de_country = lookup_helper.infer_country_from_callsign(self.de_call)
|
||||||
if self.de_call and not self.de_dxcc_id:
|
if self.de_call and not self.de_continent:
|
||||||
self.de_dxcc_id = lookup_helper.infer_dxcc_id_from_callsign(self.de_call)
|
self.de_continent = lookup_helper.infer_continent_from_callsign(self.de_call)
|
||||||
if self.de_dxcc_id and self.de_dxcc_id in DXCC_FLAGS and not self.de_flag:
|
if self.de_call and not self.de_dxcc_id:
|
||||||
self.de_flag = DXCC_FLAGS[self.de_dxcc_id]
|
self.de_dxcc_id = lookup_helper.infer_dxcc_id_from_callsign(self.de_call)
|
||||||
|
if self.de_dxcc_id and self.de_dxcc_id in DXCC_FLAGS and not self.de_flag:
|
||||||
|
self.de_flag = DXCC_FLAGS[self.de_dxcc_id]
|
||||||
|
|
||||||
# Band from frequency
|
# Band from frequency
|
||||||
if self.freq and not self.band:
|
if self.freq and not self.band:
|
||||||
@@ -165,15 +203,15 @@ class Spot:
|
|||||||
if self.mode and not self.mode_type:
|
if self.mode and not self.mode_type:
|
||||||
self.mode_type = lookup_helper.infer_mode_type_from_mode(self.mode)
|
self.mode_type = lookup_helper.infer_mode_type_from_mode(self.mode)
|
||||||
|
|
||||||
# Grid to lat/lon and vice versa
|
# DX Grid to lat/lon and vice versa
|
||||||
if self.grid and not self.latitude:
|
if self.dx_grid and not self.dx_latitude:
|
||||||
ll = locator_to_latlong(self.grid)
|
ll = locator_to_latlong(self.dx_grid)
|
||||||
self.latitude = ll[0]
|
self.dx_latitude = ll[0]
|
||||||
self.longitude = ll[1]
|
self.dx_longitude = ll[1]
|
||||||
if self.latitude and self.longitude and not self.grid:
|
if self.dx_latitude and self.dx_longitude and not self.dx_grid:
|
||||||
self.grid = latlong_to_locator(self.latitude, self.longitude, 8)
|
self.dx_grid = latlong_to_locator(self.dx_latitude, self.dx_longitude, 8)
|
||||||
if self.latitude:
|
if self.dx_latitude:
|
||||||
self.location_source = "SPOT"
|
self.dx_location_source = "SPOT"
|
||||||
|
|
||||||
# QRT comment detection
|
# QRT comment detection
|
||||||
if self.comment and not self.qrt:
|
if self.comment and not self.qrt:
|
||||||
@@ -184,26 +222,45 @@ class Spot:
|
|||||||
# the one from the park reference they're at.
|
# the one from the park reference they're at.
|
||||||
if self.dx_call and not self.dx_name:
|
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(self.dx_call)
|
||||||
if self.dx_call and not self.latitude:
|
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_qrz(self.dx_call)
|
||||||
if latlon:
|
if latlon:
|
||||||
self.latitude = latlon[0]
|
self.dx_latitude = latlon[0]
|
||||||
self.longitude = latlon[1]
|
self.dx_longitude = latlon[1]
|
||||||
self.grid = lookup_helper.infer_grid_from_callsign_qrz(self.dx_call)
|
self.dx_grid = lookup_helper.infer_grid_from_callsign_qrz(self.dx_call)
|
||||||
self.location_source = "QRZ"
|
self.dx_location_source = "QRZ"
|
||||||
|
|
||||||
# Last resort for getting a position, use the DXCC entity.
|
# Last resort for getting a DX position, use the DXCC entity.
|
||||||
if self.dx_call and not self.latitude:
|
if self.dx_call and not self.dx_latitude:
|
||||||
latlon = lookup_helper.infer_latlon_from_callsign_dxcc(self.dx_call)
|
latlon = lookup_helper.infer_latlon_from_callsign_dxcc(self.dx_call)
|
||||||
if latlon:
|
if latlon:
|
||||||
self.latitude = latlon[0]
|
self.dx_latitude = latlon[0]
|
||||||
self.longitude = latlon[1]
|
self.dx_longitude = latlon[1]
|
||||||
self.grid = lookup_helper.infer_grid_from_callsign_dxcc(self.dx_call)
|
self.dx_grid = lookup_helper.infer_grid_from_callsign_dxcc(self.dx_call)
|
||||||
self.location_source = "DXCC"
|
self.dx_location_source = "DXCC"
|
||||||
|
|
||||||
# Location is "good" if it is from a spot, or from QRZ if the callsign doesn't contain a slash, so the operator
|
# 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.
|
# is likely at home.
|
||||||
self.location_good = self.location_source == "SPOT" or (self.location_source == "QRZ" and not "/" in self.dx_call)
|
self.dx_location_good = self.dx_location_source == "SPOT" or (
|
||||||
|
self.dx_location_source == "QRZ" and not "/" in self.dx_call)
|
||||||
|
|
||||||
|
# DE of "RBNHOLE" and "SOTAMAT" are not things we can look up location for
|
||||||
|
if self.de_call != "RBNHOLE" and self.de_call != "SOTAMAT":
|
||||||
|
# DE operator position lookup, using QRZ.com.
|
||||||
|
if self.de_call and not self.de_latitude:
|
||||||
|
latlon = lookup_helper.infer_latlon_from_callsign_qrz(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)
|
||||||
|
|
||||||
|
# Last resort for getting a DE position, use the DXCC entity.
|
||||||
|
if self.de_call and not self.de_latitude:
|
||||||
|
latlon = lookup_helper.infer_latlon_from_callsign_dxcc(self.de_call)
|
||||||
|
if latlon:
|
||||||
|
self.de_latitude = latlon[0]
|
||||||
|
self.de_longitude = latlon[1]
|
||||||
|
self.de_grid = lookup_helper.infer_grid_from_callsign_dxcc(self.de_call)
|
||||||
|
|
||||||
# Always create an ID based on a hash of every parameter *except* received_time. This is used as the index
|
# 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
|
# to a map, which as a byproduct avoids us having multiple duplicate copies of the object that are identical
|
||||||
@@ -217,4 +274,4 @@ class Spot:
|
|||||||
|
|
||||||
# JSON serialise
|
# JSON serialise
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True)
|
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True)
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ class APRSIS(SpotProvider):
|
|||||||
dx_aprs_ssid=dx_aprs_ssid,
|
dx_aprs_ssid=dx_aprs_ssid,
|
||||||
de_call=data["via"],
|
de_call=data["via"],
|
||||||
comment=data["comment"] if "comment" in data else None,
|
comment=data["comment"] if "comment" in data else None,
|
||||||
latitude=data["latitude"] if "latitude" in data else None,
|
dx_latitude=data["latitude"] if "latitude" in data else None,
|
||||||
longitude=data["longitude"] if "longitude" in data else None,
|
dx_longitude=data["longitude"] if "longitude" in data else None,
|
||||||
icon="tower-cell",
|
icon="tower-cell",
|
||||||
time=datetime.now(pytz.UTC).timestamp()) # APRS-IS spots are live so we can assume spot time is "now"
|
time=datetime.now(pytz.UTC).timestamp()) # APRS-IS spots are live so we can assume spot time is "now"
|
||||||
|
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ class GMA(HTTPSpotProvider):
|
|||||||
sig_refs_names=[source_spot["NAME"]],
|
sig_refs_names=[source_spot["NAME"]],
|
||||||
time=datetime.strptime(source_spot["DATE"] + source_spot["TIME"], "%Y%m%d%H%M").replace(
|
time=datetime.strptime(source_spot["DATE"] + source_spot["TIME"], "%Y%m%d%H%M").replace(
|
||||||
tzinfo=pytz.UTC).timestamp(),
|
tzinfo=pytz.UTC).timestamp(),
|
||||||
latitude=float(source_spot["LAT"]) if (source_spot["LAT"] and source_spot["LAT"] != "") else None,
|
dx_latitude=float(source_spot["LAT"]) if (source_spot["LAT"] and source_spot["LAT"] != "") else None,
|
||||||
# Seen GMA spots with no (or empty) lat/lon
|
# Seen GMA spots with no (or empty) lat/lon
|
||||||
longitude=float(source_spot["LON"]) if (source_spot["LON"] and source_spot["LON"] != "") else None)
|
dx_longitude=float(source_spot["LON"]) if (source_spot["LON"] and source_spot["LON"] != "") else None)
|
||||||
|
|
||||||
# GMA doesn't give what programme (SIG) the reference is for until we separately look it up.
|
# GMA doesn't give what programme (SIG) the reference is for until we separately look it up.
|
||||||
ref_response = self.REF_INFO_CACHE.get(self.REF_INFO_URL_ROOT + source_spot["REF"],
|
ref_response = self.REF_INFO_CACHE.get(self.REF_INFO_URL_ROOT + source_spot["REF"],
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ class HEMA(HTTPSpotProvider):
|
|||||||
sig_refs_names=[spot_items[4]],
|
sig_refs_names=[spot_items[4]],
|
||||||
icon="mound",
|
icon="mound",
|
||||||
time=datetime.strptime(spot_items[0], "%d/%m/%Y %H:%M").replace(tzinfo=pytz.UTC).timestamp(),
|
time=datetime.strptime(spot_items[0], "%d/%m/%Y %H:%M").replace(tzinfo=pytz.UTC).timestamp(),
|
||||||
latitude=float(spot_items[7]),
|
dx_latitude=float(spot_items[7]),
|
||||||
longitude=float(spot_items[8]))
|
dx_longitude=float(spot_items[8]))
|
||||||
|
|
||||||
# Add to our list. Don't worry about de-duping, removing old spots etc. at this point; other code will do
|
# Add to our list. Don't worry about de-duping, removing old spots etc. at this point; other code will do
|
||||||
# that for us.
|
# that for us.
|
||||||
|
|||||||
@@ -63,9 +63,9 @@ class ParksNPeaks(HTTPSpotProvider):
|
|||||||
siota_dr = csv.DictReader(siota_csv_data.content.decode().splitlines())
|
siota_dr = csv.DictReader(siota_csv_data.content.decode().splitlines())
|
||||||
for row in siota_dr:
|
for row in siota_dr:
|
||||||
if row["SILO_CODE"] == spot.sig_refs[0]:
|
if row["SILO_CODE"] == spot.sig_refs[0]:
|
||||||
spot.latitude = float(row["LAT"])
|
spot.dx_latitude = float(row["LAT"])
|
||||||
spot.longitude = float(row["LON"])
|
spot.dx_longitude = float(row["LON"])
|
||||||
spot.grid = row["LOCATOR"]
|
spot.dx_grid = row["LOCATOR"]
|
||||||
break
|
break
|
||||||
|
|
||||||
# ZLOTA name/lat/lon lookup
|
# ZLOTA name/lat/lon lookup
|
||||||
@@ -74,8 +74,8 @@ class ParksNPeaks(HTTPSpotProvider):
|
|||||||
for asset in zlota_data:
|
for asset in zlota_data:
|
||||||
if asset["code"] == spot.sig_refs[0]:
|
if asset["code"] == spot.sig_refs[0]:
|
||||||
spot.sig_refs_names = [asset["name"]]
|
spot.sig_refs_names = [asset["name"]]
|
||||||
spot.latitude = asset["y"]
|
spot.dx_latitude = asset["y"]
|
||||||
spot.longitude = asset["x"]
|
spot.dx_longitude = asset["x"]
|
||||||
# Junk the "DE call", PNP always returns "ZLOTA" as the spotter for ZLOTA spots
|
# Junk the "DE call", PNP always returns "ZLOTA" as the spotter for ZLOTA spots
|
||||||
spot.de_call = None
|
spot.de_call = None
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ class POTA(HTTPSpotProvider):
|
|||||||
sig_refs_names=[source_spot["name"]],
|
sig_refs_names=[source_spot["name"]],
|
||||||
icon="tree",
|
icon="tree",
|
||||||
time=datetime.strptime(source_spot["spotTime"], "%Y-%m-%dT%H:%M:%S").replace(tzinfo=pytz.UTC).timestamp(),
|
time=datetime.strptime(source_spot["spotTime"], "%Y-%m-%dT%H:%M:%S").replace(tzinfo=pytz.UTC).timestamp(),
|
||||||
grid=source_spot["grid6"],
|
dx_grid=source_spot["grid6"],
|
||||||
latitude=source_spot["latitude"],
|
dx_latitude=source_spot["latitude"],
|
||||||
longitude=source_spot["longitude"])
|
dx_longitude=source_spot["longitude"])
|
||||||
|
|
||||||
# Add to our list. Don't worry about de-duping, removing old spots etc. at this point; other code will do
|
# Add to our list. Don't worry about de-duping, removing old spots etc. at this point; other code will do
|
||||||
# that for us.
|
# that for us.
|
||||||
|
|||||||
@@ -58,9 +58,9 @@ class SOTA(HTTPSpotProvider):
|
|||||||
try:
|
try:
|
||||||
summit_response = self.SUMMIT_DATA_CACHE.get(self.SUMMIT_URL_ROOT + source_spot["summitCode"], headers=HTTP_HEADERS)
|
summit_response = self.SUMMIT_DATA_CACHE.get(self.SUMMIT_URL_ROOT + source_spot["summitCode"], headers=HTTP_HEADERS)
|
||||||
summit_data = summit_response.json()
|
summit_data = summit_response.json()
|
||||||
spot.grid = summit_data["locator"]
|
spot.dx_grid = summit_data["locator"]
|
||||||
spot.latitude = summit_data["latitude"]
|
spot.dx_latitude = summit_data["latitude"]
|
||||||
spot.longitude = summit_data["longitude"]
|
spot.dx_longitude = summit_data["longitude"]
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.warn("Looking up summit " + source_spot["summitCode"] + " from the SOTA API failed. No summit data was available.")
|
logging.warn("Looking up summit " + source_spot["summitCode"] + " from the SOTA API failed. No summit data was available.")
|
||||||
|
|
||||||
|
|||||||
@@ -23,22 +23,22 @@ class WWBOTA(SSESpotProvider):
|
|||||||
ref_names.append(ref["name"])
|
ref_names.append(ref["name"])
|
||||||
|
|
||||||
spot = Spot(source=self.name,
|
spot = Spot(source=self.name,
|
||||||
dx_call=source_spot["call"].upper(),
|
dx_call=source_spot["call"].upper(),
|
||||||
de_call=source_spot["spotter"].upper(),
|
de_call=source_spot["spotter"].upper(),
|
||||||
freq=float(source_spot["freq"]) * 1000000,
|
freq=float(source_spot["freq"]) * 1000000,
|
||||||
mode=source_spot["mode"].upper(),
|
mode=source_spot["mode"].upper(),
|
||||||
comment=source_spot["comment"],
|
comment=source_spot["comment"],
|
||||||
sig="WWBOTA",
|
sig="WWBOTA",
|
||||||
sig_refs=refs,
|
sig_refs=refs,
|
||||||
sig_refs_names=ref_names,
|
sig_refs_names=ref_names,
|
||||||
icon="radiation",
|
icon="radiation",
|
||||||
time=datetime.fromisoformat(source_spot["time"]).timestamp(),
|
time=datetime.fromisoformat(source_spot["time"]).timestamp(),
|
||||||
# WWBOTA spots can contain multiple references for bunkers being activated simultaneously. For
|
# WWBOTA spots can contain multiple references for bunkers being activated simultaneously. For
|
||||||
# now, we will just pick the first one to use as our grid, latitude and longitude.
|
# now, we will just pick the first one to use as our grid, latitude and longitude.
|
||||||
grid=source_spot["references"][0]["locator"],
|
dx_grid=source_spot["references"][0]["locator"],
|
||||||
latitude=source_spot["references"][0]["lat"],
|
dx_latitude=source_spot["references"][0]["lat"],
|
||||||
longitude=source_spot["references"][0]["long"],
|
dx_longitude=source_spot["references"][0]["long"],
|
||||||
qrt=source_spot["type"] == "QRT")
|
qrt=source_spot["type"] == "QRT")
|
||||||
|
|
||||||
# WWBOTA does support a special "Test" spot type, we need to avoid adding that.
|
# WWBOTA does support a special "Test" spot type, we need to avoid adding that.
|
||||||
return spot if source_spot["type"] != "Test" else None
|
return spot if source_spot["type"] != "Test" else None
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ class WWFF(HTTPSpotProvider):
|
|||||||
sig_refs_names=[source_spot["reference_name"]],
|
sig_refs_names=[source_spot["reference_name"]],
|
||||||
icon="seedling",
|
icon="seedling",
|
||||||
time=datetime.fromtimestamp(source_spot["spot_time"], tz=pytz.UTC).timestamp(),
|
time=datetime.fromtimestamp(source_spot["spot_time"], tz=pytz.UTC).timestamp(),
|
||||||
latitude=source_spot["latitude"],
|
dx_latitude=source_spot["latitude"],
|
||||||
longitude=source_spot["longitude"])
|
dx_longitude=source_spot["longitude"])
|
||||||
|
|
||||||
# Add to our list. Don't worry about de-duping, removing old spots etc. at this point; other code will do
|
# Add to our list. Don't worry about de-duping, removing old spots etc. at this point; other code will do
|
||||||
# that for us.
|
# that for us.
|
||||||
|
|||||||
@@ -461,10 +461,6 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
description: Callsign of the operator that has been spotted
|
description: Callsign of the operator that has been spotted
|
||||||
example: M0TRT
|
example: M0TRT
|
||||||
de_call:
|
|
||||||
type: string
|
|
||||||
description: Callsign of the operator that has spotted them
|
|
||||||
example: M0TEST
|
|
||||||
dx_name:
|
dx_name:
|
||||||
type: string
|
type: string
|
||||||
description: Name of the operator that has been spotted
|
description: Name of the operator that has been spotted
|
||||||
@@ -473,18 +469,10 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
description: Country of the DX operator
|
description: Country of the DX operator
|
||||||
example: United Kingdom
|
example: United Kingdom
|
||||||
de_country:
|
|
||||||
type: string
|
|
||||||
description: Country of the spotter
|
|
||||||
example: United Kingdom
|
|
||||||
dx_flag:
|
dx_flag:
|
||||||
type: string
|
type: string
|
||||||
description: Country flag of the DX operator
|
description: Country flag of the DX operator
|
||||||
example: ""
|
example: ""
|
||||||
de_flag:
|
|
||||||
type: string
|
|
||||||
description: Country flag of the spotter
|
|
||||||
example: ""
|
|
||||||
dx_continent:
|
dx_continent:
|
||||||
type: string
|
type: string
|
||||||
description: Continent of the DX operator
|
description: Continent of the DX operator
|
||||||
@@ -497,26 +485,10 @@ components:
|
|||||||
- OC
|
- OC
|
||||||
- AN
|
- AN
|
||||||
example: EU
|
example: EU
|
||||||
de_continent:
|
|
||||||
type: string
|
|
||||||
enum:
|
|
||||||
- EU
|
|
||||||
- NA
|
|
||||||
- SA
|
|
||||||
- AS
|
|
||||||
- AF
|
|
||||||
- OC
|
|
||||||
- AN
|
|
||||||
description: Continent of the spotter
|
|
||||||
example: EU
|
|
||||||
dx_dxcc_id:
|
dx_dxcc_id:
|
||||||
type: integer
|
type: integer
|
||||||
description: DXCC ID of the DX operator
|
description: DXCC ID of the DX operator
|
||||||
example: 235
|
example: 235
|
||||||
de_dxcc_id:
|
|
||||||
type: integer
|
|
||||||
description: DXCC ID of the spotter
|
|
||||||
example: 235
|
|
||||||
dx_cq_zone:
|
dx_cq_zone:
|
||||||
type: integer
|
type: integer
|
||||||
description: CQ zone of the DX operator
|
description: CQ zone of the DX operator
|
||||||
@@ -529,6 +501,71 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
description: If this is an APRS spot, what SSID was the DX operator using?
|
description: If this is an APRS spot, what SSID was the DX operator using?
|
||||||
example: ""
|
example: ""
|
||||||
|
dx_grid:
|
||||||
|
type: string
|
||||||
|
description: Maidenhead grid locator for the DX spot. This could be from a geographical reference e.g. POTA, or just from the country
|
||||||
|
example: IO91aa
|
||||||
|
dx_latitude:
|
||||||
|
type: number
|
||||||
|
description: Latitude of the DX spot, in degrees. This could be from a geographical reference e.g. POTA, or from a QRZ lookup
|
||||||
|
example: 51.2345
|
||||||
|
dx_longitude:
|
||||||
|
type: number
|
||||||
|
description: Longitude of the DX spot, in degrees. This could be from a geographical reference e.g. POTA, or from a QRZ lookup
|
||||||
|
example: -1.2345
|
||||||
|
dx_location_source:
|
||||||
|
type: string
|
||||||
|
description: Where we got the DX location (grid/latitude/longitude) from. If this was from the spot itself, it's likely quite accurate, but if we had to fall back to QRZ lookup, or even a location based on the DXCC itself, it will be a lot less accurate.
|
||||||
|
enum:
|
||||||
|
- SPOT
|
||||||
|
- QRZ
|
||||||
|
- DXCC
|
||||||
|
- NONE
|
||||||
|
example: SPOT
|
||||||
|
dx_location_good:
|
||||||
|
type: boolean
|
||||||
|
description: Does the software think the location is good enough to put a marker on a map? This is true if the source is "SPOT", or alternatively if the source is "QRZ" and the callsign doesn't have a slash in it (i.e. operator likely at home).
|
||||||
|
example: true
|
||||||
|
de_call:
|
||||||
|
type: string
|
||||||
|
description: Callsign of the operator that has spotted them
|
||||||
|
example: M0TEST
|
||||||
|
de_country:
|
||||||
|
type: string
|
||||||
|
description: Country of the spotter
|
||||||
|
example: United Kingdom
|
||||||
|
de_flag:
|
||||||
|
type: string
|
||||||
|
description: Country flag of the spotter
|
||||||
|
example: ""
|
||||||
|
de_continent:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- EU
|
||||||
|
- NA
|
||||||
|
- SA
|
||||||
|
- AS
|
||||||
|
- AF
|
||||||
|
- OC
|
||||||
|
- AN
|
||||||
|
description: Continent of the spotter
|
||||||
|
example: EU
|
||||||
|
de_dxcc_id:
|
||||||
|
type: integer
|
||||||
|
description: DXCC ID of the spotter
|
||||||
|
example: 235
|
||||||
|
de_grid:
|
||||||
|
type: string
|
||||||
|
description: Maidenhead grid locator for the spotter. This is not going to be from a xOTA reference so it will likely just be a QRZ or DXCC lookup. If the spotter is also portable, this is probably wrong, but it's good enough for some simple mapping.
|
||||||
|
example: IO91aa
|
||||||
|
de_latitude:
|
||||||
|
type: number
|
||||||
|
description: Latitude of the spotter, in degrees. This is not going to be from a xOTA reference so it will likely just be a QRZ or DXCC lookup. If the spotter is also portable, this is probably wrong, but it's good enough for some simple mapping.
|
||||||
|
example: 51.2345
|
||||||
|
de_longitude:
|
||||||
|
type: number
|
||||||
|
description: Longitude of the DX spotspotter, in degrees. This is not going to be from a xOTA reference so it will likely just be a QRZ or DXCC lookup. If the spotter is also portable, this is probably wrong, but it's good enough for some simple mapping.
|
||||||
|
example: -1.2345
|
||||||
mode:
|
mode:
|
||||||
type: string
|
type: string
|
||||||
description: Reported mode.
|
description: Reported mode.
|
||||||
@@ -651,31 +688,6 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
descripton: Icon, from the Font Awesome set. This is fairly opinionated but is here to help the Spothole web UI and Field Spotter. Does not include the "fa-" prefix.
|
descripton: Icon, from the Font Awesome set. This is fairly opinionated but is here to help the Spothole web UI and Field Spotter. Does not include the "fa-" prefix.
|
||||||
example: tree
|
example: tree
|
||||||
grid:
|
|
||||||
type: string
|
|
||||||
description: Maidenhead grid locator for the spot. This could be from a geographical reference e.g. POTA, or just from the country
|
|
||||||
example: IO91aa
|
|
||||||
latitude:
|
|
||||||
type: number
|
|
||||||
description: Latitude, in degrees. This could be from a geographical reference e.g. POTA, or from a QRZ lookup
|
|
||||||
example: 51.2345
|
|
||||||
longitude:
|
|
||||||
type: number
|
|
||||||
description: Latitude, in degrees. This could be from a geographical reference e.g. POTA, or from a QRZ lookup
|
|
||||||
example: -1.2345
|
|
||||||
location_source:
|
|
||||||
type: string
|
|
||||||
description: Where we got the location (grid/latitude/longitude) from. If this was from the spot itself, it's likely quite accurate, but if we had to fall back to QRZ lookup, or even a location based on the DXCC itself, it will be a lot less accurate.
|
|
||||||
enum:
|
|
||||||
- SPOT
|
|
||||||
- QRZ
|
|
||||||
- DXCC
|
|
||||||
- NONE
|
|
||||||
example: SPOT
|
|
||||||
location_good:
|
|
||||||
type: boolean
|
|
||||||
description: Does the software think the location is good enough to put a marker on a map? This is true if the source is "SPOT", or alternatively if the source is "QRZ" and the callsign doesn't have a slash in it (i.e. operator likely at home).
|
|
||||||
example: true
|
|
||||||
qrt:
|
qrt:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: QRT state. Some APIs return spots marked as QRT. Otherwise we can check the comments.
|
description: QRT state. Some APIs return spots marked as QRT. Otherwise we can check the comments.
|
||||||
|
|||||||
@@ -134,11 +134,11 @@ function updateTable() {
|
|||||||
|
|
||||||
// Format bearing text
|
// Format bearing text
|
||||||
var bearingText = "---<span class='bearing-q hideonmobile'><i class='fa-solid fa-circle-question' title='The position was not reported via the spotting service, and we could not determine one. A bearing to this DX is not available.'></i></span>";
|
var bearingText = "---<span class='bearing-q hideonmobile'><i class='fa-solid fa-circle-question' title='The position was not reported via the spotting service, and we could not determine one. A bearing to this DX is not available.'></i></span>";
|
||||||
if (userPos != null && s["latitude"] != null && s["longitude"] != null) {
|
if (userPos != null && s["dx_latitude"] != null && s["dx_longitude"] != null) {
|
||||||
var bearing = calcBearing(userPos[0], userPos[1], s["latitude"], s["longitude"]);
|
var bearing = calcBearing(userPos[0], userPos[1], s["dx_latitude"], s["dx_longitude"]);
|
||||||
bearingText = bearing.toFixed(0).padStart(3, '0') + "°";
|
bearingText = bearing.toFixed(0).padStart(3, '0') + "°";
|
||||||
if (s["location_good"] == null || s["location_good"] == false) {
|
if (s["dx_location_good"] == null || s["dx_location_good"] == false) {
|
||||||
if (s["location_source"] == "QRZ") {
|
if (s["dx_location_source"] == "QRZ") {
|
||||||
bearingText = bearingText + "<span class='bearing-q hideonmobile'><i class='fa-solid fa-circle-question' title='The position was not reported via the spotting service. We had to fall back to a QRZ \"home\" location for a portable/mobile/alternative spot, so this bearing may not be accurate if the DX is close to you..'></i></span>";
|
bearingText = bearingText + "<span class='bearing-q hideonmobile'><i class='fa-solid fa-circle-question' title='The position was not reported via the spotting service. We had to fall back to a QRZ \"home\" location for a portable/mobile/alternative spot, so this bearing may not be accurate if the DX is close to you..'></i></span>";
|
||||||
} else {
|
} else {
|
||||||
bearingText = bearingText + "<span class='bearing-q hideonmobile'><i class='fa-solid fa-circle-question' title='The position was not reported via the spotting service. We had to fall back to just using the centre of a DXCC entity, so this bearing may not be accurate if the DX is close to you.'></i></span>";
|
bearingText = bearingText + "<span class='bearing-q hideonmobile'><i class='fa-solid fa-circle-question' title='The position was not reported via the spotting service. We had to fall back to just using the centre of a DXCC entity, so this bearing may not be accurate if the DX is close to you.'></i></span>";
|
||||||
|
|||||||
Reference in New Issue
Block a user