First attempt at converting "sig" to "activity" for v3

This commit is contained in:
Ian Renton
2026-09-24 07:09:37 +01:00
parent 1d0129f7bb
commit d91fa70655
90 changed files with 822 additions and 496 deletions
+35 -35
View File
@@ -68,10 +68,10 @@ class GMA(HTTPSpotProvider):
# Filter out some weird mode strings
mode=Mode.from_name(source_spot["MODE"].upper()) if "<>" not in source_spot["MODE"] else None,
comment=source_spot["TEXT"],
sig_refs=[
activity_refs=[
ActivityRef(
id=source_spot["REF"],
sig="",
activity="",
name=source_spot["NAME"],
latitude=lat,
longitude=lon,
@@ -98,57 +98,57 @@ class GMA(HTTPSpotProvider):
and ref_response.text != "\n"
):
ref_info = ref_response.json()
if spot.sig_refs and ref_info and "reftype" in ref_info:
if spot.activity_refs and ref_info and "reftype" in ref_info:
match ref_info["reftype"]:
case "Summit":
# Summits are a bit complicated, they can be SOTA or GMA depending on the
# separate "sota" field:
if "sota" in ref_info and ref_info["sota"] != "":
spot.sig_refs[0].sig = ActivityName.SOTA
spot.sig_refs[0].ref_type = ActivityRefType.SUMMIT
spot.sig = ActivityName.SOTA
spot.activity_refs[0].activity = ActivityName.SOTA
spot.activity_refs[0].ref_type = ActivityRefType.SUMMIT
spot.activity = ActivityName.SOTA
else:
spot.sig_refs[0].sig = ActivityName.GMA
spot.sig_refs[0].ref_type = ActivityRefType.SUMMIT
spot.sig = ActivityName.GMA
spot.activity_refs[0].activity = ActivityName.GMA
spot.activity_refs[0].ref_type = ActivityRefType.SUMMIT
spot.activity = ActivityName.GMA
case "POTA":
spot.sig_refs[0].sig = ActivityName.POTA
spot.sig_refs[0].ref_type = ActivityRefType.PARK
spot.sig = ActivityName.POTA
spot.activity_refs[0].activity = ActivityName.POTA
spot.activity_refs[0].ref_type = ActivityRefType.PARK
spot.activity = ActivityName.POTA
case "WWFF":
spot.sig_refs[0].sig = ActivityName.WWFF
spot.sig_refs[0].ref_type = ActivityRefType.PARK
spot.sig = ActivityName.WWFF
spot.activity_refs[0].activity = ActivityName.WWFF
spot.activity_refs[0].ref_type = ActivityRefType.PARK
spot.activity = ActivityName.WWFF
case "IOTA Island":
spot.sig_refs[0].sig = ActivityName.IOTA
spot.sig_refs[0].ref_type = ActivityRefType.ISLAND
spot.sig = ActivityName.IOTA
spot.activity_refs[0].activity = ActivityName.IOTA
spot.activity_refs[0].ref_type = ActivityRefType.ISLAND
spot.activity = ActivityName.IOTA
case "GMA Island":
spot.sig_refs[0].sig = ActivityName.GMA_ISLANDS
spot.sig_refs[0].ref_type = ActivityRefType.ISLAND
spot.sig = ActivityName.GMA_ISLANDS
spot.activity_refs[0].activity = ActivityName.GMA_ISLANDS
spot.activity_refs[0].ref_type = ActivityRefType.ISLAND
spot.activity = ActivityName.GMA_ISLANDS
case "Lighthouse (ILLW)":
spot.sig_refs[0].sig = ActivityName.ILLW
spot.sig_refs[0].ref_type = ActivityRefType.LIGHTHOUSE
spot.sig = ActivityName.ILLW
spot.activity_refs[0].activity = ActivityName.ILLW
spot.activity_refs[0].ref_type = ActivityRefType.LIGHTHOUSE
spot.activity = ActivityName.ILLW
case "Lighthouse (ARLHS)":
spot.sig_refs[0].sig = ActivityName.ARLHS
spot.sig_refs[0].ref_type = ActivityRefType.LIGHTHOUSE
spot.sig = ActivityName.ARLHS
spot.activity_refs[0].activity = ActivityName.ARLHS
spot.activity_refs[0].ref_type = ActivityRefType.LIGHTHOUSE
spot.activity = ActivityName.ARLHS
case "Castle":
spot.sig_refs[0].sig = ActivityName.WCA
spot.sig_refs[0].ref_type = ActivityRefType.CASTLE
spot.sig = ActivityName.WCA
spot.activity_refs[0].activity = ActivityName.WCA
spot.activity_refs[0].ref_type = ActivityRefType.CASTLE
spot.activity = ActivityName.WCA
case "Mill":
spot.sig_refs[0].sig = ActivityName.MOTA
spot.sig_refs[0].ref_type = ActivityRefType.MILL
spot.sig = ActivityName.MOTA
spot.activity_refs[0].activity = ActivityName.MOTA
spot.activity_refs[0].ref_type = ActivityRefType.MILL
spot.activity = ActivityName.MOTA
case _:
logger.warning(
f"GMA spot found with ref type {ref_info['reftype']}, developer needs to add support for this!"
)
spot.sig_refs[0].sig = ref_info["reftype"]
spot.sig = ref_info["reftype"]
spot.activity_refs[0].activity = ref_info["reftype"]
spot.activity = ref_info["reftype"]
elif not ref_response.from_cache:
if not ref_response.ok:
+3 -3
View File
@@ -62,11 +62,11 @@ class HEMA(HTTPSpotProvider):
freq=float(freq_mode_match.group(1)) * 1000000,
mode=Mode.from_name(freq_mode_match.group(2).upper()),
comment=spotter_comment_match.group(2),
sig=ActivityName.HEMA,
sig_refs=[
activity=ActivityName.HEMA,
activity_refs=[
ActivityRef(
id=spot_items[3].upper(),
sig=ActivityName.HEMA,
activity=ActivityName.HEMA,
name=spot_items[4],
latitude=float(spot_items[7]),
longitude=float(spot_items[8]),
+3 -3
View File
@@ -34,11 +34,11 @@ class LLOTA(HTTPSpotProvider):
freq=float(source_spot["frequency"]) * 1000000,
mode=Mode.from_name(source_spot["mode"].upper()),
comment=comment,
sig=ActivityName.LLOTA,
sig_refs=[
activity=ActivityName.LLOTA,
activity_refs=[
ActivityRef(
id=source_spot["reference"],
sig=ActivityName.LLOTA,
activity=ActivityName.LLOTA,
name=source_spot["reference_name"],
ref_type=ActivityRefType.LAKE,
)
+5 -5
View File
@@ -70,20 +70,20 @@ class ParksNPeaks(HTTPSpotProvider):
ref_id = source_spot["actSiteID"]
if activity:
spot.sig = activity
spot.activity = activity
if ref_id:
activity_refs = [
ActivityRef(
id=ref_id,
sig=activity,
activity=activity,
# Free text location is not present in all spots, so only add it if it's set
name=source_spot["actLocation"]
if "actLocation" in source_spot and source_spot["actLocation"] != ""
else None,
)
]
spot.sig_refs = activity_refs
spot.activity_refs = activity_refs
else:
# If no actSiteID is set, e.g. because actClass is "QRP", sometimes we still have an actLocation
@@ -128,9 +128,9 @@ class ParksNPeaks(HTTPSpotProvider):
raise ValueError(
"Parks N Peaks user ID and API key are required. Get yours from your Parks N Peaks account."
)
ref_id = spot.sig_refs[0].id if spot.sig_refs else ""
ref_id = spot.activity_refs[0].id if spot.activity_refs else ""
body = {
"actClass": spot.sig or "",
"actClass": spot.activity or "",
"actCallsign": spot.dx_call,
"actSite": ref_id,
"mode": spot.mode or "",
+6 -6
View File
@@ -33,11 +33,11 @@ class POTA(HTTPSpotProvider):
freq=float(source_spot["frequency"]) * 1000 if source_spot["frequency"] != "INVALID" else None,
mode=Mode.from_name(source_spot["mode"].upper()),
comment=source_spot["comments"],
sig=ActivityName.POTA,
sig_refs=[
activity=ActivityName.POTA,
activity_refs=[
ActivityRef(
id=source_spot["reference"],
sig=ActivityName.POTA,
activity=ActivityName.POTA,
name=source_spot["name"],
latitude=source_spot["latitude"],
longitude=source_spot["longitude"],
@@ -61,14 +61,14 @@ class POTA(HTTPSpotProvider):
return activity == ActivityName.POTA
def submit_spot(self, spot, credentials):
sig_ref = spot.sig_refs[0].id if spot.sig_refs else None
if sig_ref:
ref_id = spot.activity_refs[0].id if spot.activity_refs else None
if ref_id:
body = {
"activator": spot.dx_call,
"spotter": spot.de_call,
"frequency": str(spot.freq / 1000.0),
"mode": spot.mode or "",
"reference": sig_ref,
"reference": ref_id,
"comments": spot.comment or "",
"source": "Spothole",
}
+6 -6
View File
@@ -57,11 +57,11 @@ class SOTA(HTTPSpotProvider):
# Seen SOTA spots with no frequency!
mode=Mode.from_name(source_spot["mode"].upper()),
comment=source_spot["comments"],
sig=ActivityName.SOTA,
sig_refs=[
activity=ActivityName.SOTA,
activity_refs=[
ActivityRef(
id=source_spot["summitCode"],
sig=ActivityName.SOTA,
activity=ActivityName.SOTA,
name=source_spot["summitName"],
latitude=source_spot["latitude"],
longitude=source_spot["longitude"],
@@ -92,10 +92,10 @@ class SOTA(HTTPSpotProvider):
id_token = credentials.get("id_token", "")
if not access_token or not id_token:
raise ValueError("SOTA API tokens are required. Please log into SOTA in order to spot to it.")
sig_ref = spot.sig_refs[0].id if spot.sig_refs else ""
if sig_ref:
ref_id = spot.activity_refs[0].id if spot.activity_refs else ""
if ref_id:
# Split reference into association and summit codes
ref_split = sig_ref.split("/")
ref_split = ref_id.split("/")
# Figure out a valid mode. Borrowed this from PoLo :)
# https://github.com/ham2k/app-polo/blob/main/src/extensions/activities/sota/SOTAPostSelfSpot.js
+3 -3
View File
@@ -59,13 +59,13 @@ class Tiles(HTTPSpotProvider):
freq=freq,
mode=Mode.from_name(source_spot["mode"].upper()),
comment=source_spot["notes"],
sig=ActivityName.TILES,
activity=ActivityName.TILES,
# Tiles spots can include POTA & SOTA references, but ignore those on the basis that we will get them separately from the POTA/SOTA providers anyway.
# Just take the grid reference itself as the single Tiles activity reference.
sig_refs=[
activity_refs=[
ActivityRef(
id=source_spot["maidenhead_grid"],
sig=ActivityName.TILES,
activity=ActivityName.TILES,
name=source_spot["maidenhead_grid"],
latitude=source_spot["latitude"],
longitude=source_spot["longitude"],
+4 -2
View File
@@ -34,8 +34,10 @@ class Towers(HTTPSpotProvider):
dx_call=source_spot["call"].upper(),
freq=likely_freq,
comment=source_spot["comment"],
sig=ActivityName.TOWERS,
sig_refs=[ActivityRef(id=source_spot["ref"], sig=ActivityName.TOWERS, ref_type=ActivityRefType.TOWER)],
activity=ActivityName.TOWERS,
activity_refs=[
ActivityRef(id=source_spot["ref"], activity=ActivityName.TOWERS, ref_type=ActivityRefType.TOWER)
],
time=datetime.strptime(response_json["updated"][:10] + source_spot["time"], "%Y-%m-%d%H:%M")
.replace(tzinfo=pytz.utc)
.timestamp(),
+7 -3
View File
@@ -92,9 +92,13 @@ class WOTA(HTTPSpotProvider):
freq=freq_hz,
mode=Mode.from_name(mode),
comment=comment,
sig=ActivityName.WOTA,
sig_refs=(
[ActivityRef(id=ref, sig=ActivityName.WOTA, name=ref_name, ref_type=ActivityRefType.SUMMIT)]
activity=ActivityName.WOTA,
activity_refs=(
[
ActivityRef(
id=ref, activity=ActivityName.WOTA, name=ref_name, ref_type=ActivityRefType.SUMMIT
)
]
if ref
else []
),
+3 -3
View File
@@ -23,7 +23,7 @@ class WWBOTA(SSESpotProvider):
for ref in source_spot["references"]:
activity_ref = ActivityRef(
id=ref["reference"],
sig=ActivityName.WWBOTA,
activity=ActivityName.WWBOTA,
name=ref["name"],
latitude=ref["lat"],
longitude=ref["long"],
@@ -38,8 +38,8 @@ class WWBOTA(SSESpotProvider):
freq=float(source_spot["freq"]) * 1000000,
mode=Mode.from_name(source_spot["mode"].upper()) if source_spot.get("mode") else None,
comment=source_spot["comment"],
sig=ActivityName.WWBOTA,
sig_refs=refs,
activity=ActivityName.WWBOTA,
activity_refs=refs,
time=datetime.fromisoformat(source_spot["time"].replace("Z", "+00:00")).timestamp(),
# 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.
+3 -3
View File
@@ -30,11 +30,11 @@ class WWFF(HTTPSpotProvider):
freq=float(source_spot["frequency_khz"]) * 1000,
mode=Mode.from_name(source_spot["mode"].upper()),
comment=source_spot["remarks"],
sig=ActivityName.WWFF,
sig_refs=[
activity=ActivityName.WWFF,
activity_refs=[
ActivityRef(
id=source_spot["reference"],
sig=ActivityName.WWFF,
activity=ActivityName.WWFF,
name=source_spot["reference_name"],
latitude=source_spot["latitude"],
longitude=source_spot["longitude"],
+9 -7
View File
@@ -14,16 +14,18 @@ class XOTA(WebsocketSpotProvider):
The provider typically doesn't give us a lat/lon or activity explicitly, so our own config provides an activity
which we can then use for lookups. This functionality is implemented for Toilets on the Air events, of which
there are several - so a plain lookup of a "TOTA reference" doesn't make sense, it depends on which TOTA, which
is why we also provide a sig_ref_prefix in our config. This is applied to the reference ID, so e.g. "T-01" at C3
might become "C3 T-01". This allows us to provide location lookups for TOTA at several conferences."""
is why we also provide an activity_ref_prefix in our config. This is applied to the reference ID, so e.g. "T-01"
at C3 might become "C3 T-01". This allows us to provide location lookups for TOTA at several conferences."""
ACTIVITY = None
def __init__(self, provider_config):
name = provider_config.get("name", "xOTA")
super().__init__(name, provider_config, provider_config["url"])
self.ACTIVITY = str(provider_config["sig"]) if "sig" in provider_config else None
self._activity_ref_prefix = str(provider_config["sig_ref_prefix"]) if "sig_ref_prefix" in provider_config else ""
self.ACTIVITY = str(provider_config["activity"]) if "activity" in provider_config else None
self._activity_ref_prefix = (
str(provider_config["activity_ref_prefix"]) if "activity_ref_prefix" in provider_config else ""
)
def _ws_message_to_spot(self, b):
string = b.decode("utf-8")
@@ -35,11 +37,11 @@ class XOTA(WebsocketSpotProvider):
dx_call=source_spot["stationCallSign"].upper(),
freq=float(source_spot["freq"]) * 1000,
mode=Mode.from_name(source_spot["mode"].upper()),
sig=self.ACTIVITY,
sig_refs=[
activity=self.ACTIVITY,
activity_refs=[
ActivityRef(
id=ref_id,
sig=self.ACTIVITY or "",
activity=self.ACTIVITY or "",
url=source_spot["reference"]["website"],
)
],
+3 -3
View File
@@ -35,11 +35,11 @@ class ZLOTA(HTTPSpotProvider):
freq=freq_hz,
mode=Mode.from_name(source_spot["mode"].upper().strip()),
comment=source_spot["comments"],
sig=ActivityName.ZLOTA,
sig_refs=[
activity=ActivityName.ZLOTA,
activity_refs=[
ActivityRef(
id=source_spot["reference"],
sig=ActivityName.ZLOTA,
activity=ActivityName.ZLOTA,
name=source_spot["name"],
)
],