Extract SIG and SIG_INFO from cluster spots. Closes #47

This commit is contained in:
Ian Renton
2025-10-20 11:05:45 +01:00
parent a21782cb62
commit 20977e59cf
16 changed files with 44 additions and 6 deletions

View File

@@ -4,6 +4,7 @@ from datetime import datetime
import pytz import pytz
from alertproviders.http_alert_provider import HTTPAlertProvider from alertproviders.http_alert_provider import HTTPAlertProvider
from core.utils import get_icon_for_sig
from data.alert import Alert from data.alert import Alert
@@ -39,6 +40,7 @@ class ParksNPeaks(HTTPAlertProvider):
sig=source_alert["Class"], sig=source_alert["Class"],
sig_refs=[sig_ref], sig_refs=[sig_ref],
sig_refs_names=[sig_ref_name], sig_refs_names=[sig_ref_name],
icon=get_icon_for_sig(source_alert["Class"]),
start_time=start_time, start_time=start_time,
is_dxpedition=False) is_dxpedition=False)

View File

@@ -3,6 +3,7 @@ from datetime import datetime
import pytz import pytz
from alertproviders.http_alert_provider import HTTPAlertProvider from alertproviders.http_alert_provider import HTTPAlertProvider
from core.utils import get_icon_for_sig
from data.alert import Alert from data.alert import Alert
@@ -27,6 +28,7 @@ class POTA(HTTPAlertProvider):
sig="POTA", sig="POTA",
sig_refs=[source_alert["reference"]], sig_refs=[source_alert["reference"]],
sig_refs_names=[source_alert["name"]], sig_refs_names=[source_alert["name"]],
icon=get_icon_for_sig("POTA"),
start_time=datetime.strptime(source_alert["startDate"] + source_alert["startTime"], start_time=datetime.strptime(source_alert["startDate"] + source_alert["startTime"],
"%Y-%m-%d%H:%M").replace(tzinfo=pytz.UTC).timestamp(), "%Y-%m-%d%H:%M").replace(tzinfo=pytz.UTC).timestamp(),
end_time=datetime.strptime(source_alert["endDate"] + source_alert["endTime"], end_time=datetime.strptime(source_alert["endDate"] + source_alert["endTime"],

View File

@@ -3,6 +3,7 @@ from datetime import datetime
import pytz import pytz
from alertproviders.http_alert_provider import HTTPAlertProvider from alertproviders.http_alert_provider import HTTPAlertProvider
from core.utils import get_icon_for_sig
from data.alert import Alert from data.alert import Alert
@@ -28,6 +29,7 @@ class SOTA(HTTPAlertProvider):
sig="SOTA", sig="SOTA",
sig_refs=[source_alert["associationCode"] + "/" + source_alert["summitCode"]], sig_refs=[source_alert["associationCode"] + "/" + source_alert["summitCode"]],
sig_refs_names=[source_alert["summitDetails"]], sig_refs_names=[source_alert["summitDetails"]],
icon=get_icon_for_sig("SOTA"),
start_time=datetime.strptime(source_alert["dateActivated"], start_time=datetime.strptime(source_alert["dateActivated"],
"%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=pytz.UTC).timestamp(), "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=pytz.UTC).timestamp(),
is_dxpedition=False) is_dxpedition=False)

View File

@@ -3,6 +3,7 @@ from datetime import datetime
import pytz import pytz
from alertproviders.http_alert_provider import HTTPAlertProvider from alertproviders.http_alert_provider import HTTPAlertProvider
from core.utils import get_icon_for_sig
from data.alert import Alert from data.alert import Alert
@@ -26,6 +27,7 @@ class WWFF(HTTPAlertProvider):
comment=source_alert["remarks"], comment=source_alert["remarks"],
sig="WWFF", sig="WWFF",
sig_refs=[source_alert["reference"]], sig_refs=[source_alert["reference"]],
icon=get_icon_for_sig("WWFF"),
start_time=datetime.strptime(source_alert["utc_start"], start_time=datetime.strptime(source_alert["utc_start"],
"%Y-%m-%d %H:%M:%S").replace(tzinfo=pytz.UTC).timestamp(), "%Y-%m-%d %H:%M:%S").replace(tzinfo=pytz.UTC).timestamp(),
end_time=datetime.strptime(source_alert["utc_end"], end_time=datetime.strptime(source_alert["utc_end"],

View File

@@ -21,7 +21,7 @@ SIGS = [
SIG(name="MOTA", description="Mills on the Air", icon="fan"), SIG(name="MOTA", description="Mills on the Air", icon="fan"),
SIG(name="ARLHS", description="Amateur Radio Lighthouse Society", icon="tower-observation"), SIG(name="ARLHS", description="Amateur Radio Lighthouse Society", icon="tower-observation"),
SIG(name="ILLW", description="International Lighthouse & Lightship Weekend", icon="tower-observation"), SIG(name="ILLW", description="International Lighthouse & Lightship Weekend", icon="tower-observation"),
SIG(name="SiOTA", description="Silos on the Air", icon="wheat-awn"), SIG(name="SIOTA", description="Silos on the Air", icon="wheat-awn"),
SIG(name="WCA", description="World Castles Award", icon="chess-rook"), SIG(name="WCA", description="World Castles Award", icon="chess-rook"),
SIG(name="ZLOTA", description="New Zealand on the Air", icon="kiwi-bird"), SIG(name="ZLOTA", description="New Zealand on the Air", icon="kiwi-bird"),
SIG(name="KRMNPA", description="Keith Roget Memorial National Parks Award", icon="earth-oceania") SIG(name="KRMNPA", description="Keith Roget Memorial National Parks Award", icon="earth-oceania")

View File

@@ -6,3 +6,9 @@ def get_icon_for_sig(sig):
if s.name == sig: if s.name == sig:
return s.icon return s.icon
return "circle-question" return "circle-question"
# Regex matching any SIG
ANY_SIG_REGEX = r"(" + r"|".join(list(map(lambda p: p.name, SIGS))) + r")"
# Regex matching any SIG reference
ANY_SIG_REF_REGEX = r"[\w\/]+\-\d+"

View File

@@ -9,7 +9,7 @@ import pytz
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
from core.utility_functions import get_icon_for_sig from core.utils import get_icon_for_sig
# Data class that defines an alert. # Data class that defines an alert.

View File

@@ -11,7 +11,7 @@ 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
from core.utility_functions import get_icon_for_sig from core.utils import get_icon_for_sig
# Data class that defines a spot. # Data class that defines a spot.

View File

@@ -7,6 +7,8 @@ from time import sleep
import pytz import pytz
import telnetlib3 import telnetlib3
from core.constants import SIGS
from core.utils import ANY_SIG_REGEX, ANY_SIG_REF_REGEX, get_icon_for_sig
from data.spot import Spot from data.spot import Spot
from core.config import SERVER_OWNER_CALLSIGN from core.config import SERVER_OWNER_CALLSIGN
from spotproviders.spot_provider import SpotProvider from spotproviders.spot_provider import SpotProvider
@@ -75,7 +77,15 @@ class DXCluster(SpotProvider):
icon="desktop", icon="desktop",
time=spot_datetime.timestamp()) time=spot_datetime.timestamp())
# See if the comment looks like it contains a SIG (and optionally SIG reference) # See if the comment looks like it contains a SIG (and optionally SIG reference). Currently,
# only one sig ref is supported.
sig_match = re.search(r"(^|\W)" + ANY_SIG_REGEX + r"($|\W)", spot.comment, re.IGNORECASE)
if sig_match:
spot.sig = sig_match.group(2).upper()
spot.icon = get_icon_for_sig(spot.sig)
sig_ref_match = re.search(r"(^|\W)" + spot.sig + r"($|\W)(" + ANY_SIG_REF_REGEX + r")($|\W)", spot.comment, re.IGNORECASE)
if sig_ref_match:
spot.sig_refs = [sig_ref_match.group(3).upper()]
# Add to our list # Add to our list
self.submit(spot) self.submit(spot)

View File

@@ -5,6 +5,7 @@ import pytz
from requests_cache import CachedSession from requests_cache import CachedSession
from core.constants import HTTP_HEADERS from core.constants import HTTP_HEADERS
from core.utils import get_icon_for_sig
from data.spot import Spot from data.spot import Spot
from spotproviders.http_spot_provider import HTTPSpotProvider from spotproviders.http_spot_provider import HTTPSpotProvider
@@ -71,6 +72,7 @@ class GMA(HTTPSpotProvider):
logging.warn("GMA spot found with ref type " + ref_info[ logging.warn("GMA spot found with ref type " + ref_info[
"reftype"] + ", developer needs to add support for this!") "reftype"] + ", developer needs to add support for this!")
spot.sig = ref_info["reftype"] spot.sig = ref_info["reftype"]
spot.icon = get_icon_for_sig(spot.sig)
# 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.

View File

@@ -5,6 +5,7 @@ import pytz
import requests import requests
from core.constants import HTTP_HEADERS from core.constants import HTTP_HEADERS
from core.utils import get_icon_for_sig
from data.spot import Spot from data.spot import Spot
from spotproviders.http_spot_provider import HTTPSpotProvider from spotproviders.http_spot_provider import HTTPSpotProvider
@@ -54,6 +55,7 @@ class HEMA(HTTPSpotProvider):
sig="HEMA", sig="HEMA",
sig_refs=[spot_items[3].upper()], sig_refs=[spot_items[3].upper()],
sig_refs_names=[spot_items[4]], sig_refs_names=[spot_items[4]],
icon=get_icon_for_sig("HEMA"),
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(),
dx_latitude=float(spot_items[7]), dx_latitude=float(spot_items[7]),
dx_longitude=float(spot_items[8])) dx_longitude=float(spot_items[8]))

View File

@@ -7,6 +7,7 @@ import pytz
from requests_cache import CachedSession from requests_cache import CachedSession
from core.constants import HTTP_HEADERS from core.constants import HTTP_HEADERS
from core.utils import get_icon_for_sig
from data.spot import Spot from data.spot import Spot
from spotproviders.http_spot_provider import HTTPSpotProvider from spotproviders.http_spot_provider import HTTPSpotProvider
@@ -41,6 +42,7 @@ class ParksNPeaks(HTTPSpotProvider):
comment=source_spot["actComments"], comment=source_spot["actComments"],
sig=source_spot["actClass"], sig=source_spot["actClass"],
sig_refs=[source_spot["actSiteID"]], sig_refs=[source_spot["actSiteID"]],
icon=get_icon_for_sig(source_spot["actClass"]),
time=datetime.strptime(source_spot["actTime"], "%Y-%m-%d %H:%M:%S").replace( time=datetime.strptime(source_spot["actTime"], "%Y-%m-%d %H:%M:%S").replace(
tzinfo=pytz.UTC).timestamp()) tzinfo=pytz.UTC).timestamp())
@@ -50,7 +52,7 @@ class ParksNPeaks(HTTPSpotProvider):
# Extract a de_call if it's in the comment but not in the "actSpoter" field # Extract a de_call if it's in the comment but not in the "actSpoter" field
m = re.search(r"\(de ([A-Za-z0-9]*)\)", spot.comment) m = re.search(r"\(de ([A-Za-z0-9]*)\)", spot.comment)
if (not spot.de_call or spot.de_call == "ZLOTA") and m is not None: if (not spot.de_call or spot.de_call == "ZLOTA") and m:
spot.de_call = m.group(1) spot.de_call = m.group(1)
# Log a warning for the developer if PnP gives us an unknown programme we've never seen before # Log a warning for the developer if PnP gives us an unknown programme we've never seen before

View File

@@ -2,6 +2,7 @@ from datetime import datetime
import pytz import pytz
from core.utils import get_icon_for_sig
from data.spot import Spot from data.spot import Spot
from spotproviders.http_spot_provider import HTTPSpotProvider from spotproviders.http_spot_provider import HTTPSpotProvider
@@ -30,6 +31,7 @@ class POTA(HTTPSpotProvider):
sig_refs=[source_spot["reference"]], sig_refs=[source_spot["reference"]],
sig_refs_names=[source_spot["name"]], sig_refs_names=[source_spot["name"]],
sig_refs_urls=["https://pota.app/#/park/" + source_spot["reference"]], sig_refs_urls=["https://pota.app/#/park/" + source_spot["reference"]],
icon=get_icon_for_sig("POTA"),
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(),
dx_grid=source_spot["grid6"], dx_grid=source_spot["grid6"],
dx_latitude=source_spot["latitude"], dx_latitude=source_spot["latitude"],

View File

@@ -5,6 +5,7 @@ import requests
from requests_cache import CachedSession from requests_cache import CachedSession
from core.constants import HTTP_HEADERS from core.constants import HTTP_HEADERS
from core.utils import get_icon_for_sig
from data.spot import Spot from data.spot import Spot
from spotproviders.http_spot_provider import HTTPSpotProvider from spotproviders.http_spot_provider import HTTPSpotProvider
@@ -51,6 +52,7 @@ class SOTA(HTTPSpotProvider):
sig_refs=[source_spot["summitCode"]], sig_refs=[source_spot["summitCode"]],
sig_refs_names=[source_spot["summitName"]], sig_refs_names=[source_spot["summitName"]],
sig_refs_urls=["https://www.sotadata.org.uk/en/summit/" + source_spot["summitCode"]], sig_refs_urls=["https://www.sotadata.org.uk/en/summit/" + source_spot["summitCode"]],
icon=get_icon_for_sig("SOTA"),
time=datetime.fromisoformat(source_spot["timeStamp"]).timestamp(), time=datetime.fromisoformat(source_spot["timeStamp"]).timestamp(),
activation_score=source_spot["points"]) activation_score=source_spot["points"])

View File

@@ -1,6 +1,7 @@
import json import json
from datetime import datetime from datetime import datetime
from core.utils import get_icon_for_sig
from data.spot import Spot from data.spot import Spot
from spotproviders.sse_spot_provider import SSESpotProvider from spotproviders.sse_spot_provider import SSESpotProvider
@@ -38,6 +39,7 @@ class WWBOTA(SSESpotProvider):
sig="WWBOTA", sig="WWBOTA",
sig_refs=refs, sig_refs=refs,
sig_refs_names=ref_names, sig_refs_names=ref_names,
icon=get_icon_for_sig("WWBOTA"),
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.

View File

@@ -2,6 +2,7 @@ from datetime import datetime
import pytz import pytz
from core.utils import get_icon_for_sig
from data.spot import Spot from data.spot import Spot
from spotproviders.http_spot_provider import HTTPSpotProvider from spotproviders.http_spot_provider import HTTPSpotProvider
@@ -30,6 +31,7 @@ class WWFF(HTTPSpotProvider):
sig_refs=[source_spot["reference"]], sig_refs=[source_spot["reference"]],
sig_refs_names=[source_spot["reference_name"]], sig_refs_names=[source_spot["reference_name"]],
sig_refs_urls=["https://wwff.co/directory/?showRef=" + source_spot["reference"]], sig_refs_urls=["https://wwff.co/directory/?showRef=" + source_spot["reference"]],
icon=get_icon_for_sig("WWFF"),
time=datetime.fromtimestamp(source_spot["spot_time"], tz=pytz.UTC).timestamp(), time=datetime.fromtimestamp(source_spot["spot_time"], tz=pytz.UTC).timestamp(),
dx_latitude=source_spot["latitude"], dx_latitude=source_spot["latitude"],
dx_longitude=source_spot["longitude"]) dx_longitude=source_spot["longitude"])