Add EME SIG and do some refactoring

This commit is contained in:
Ian Renton
2026-09-11 08:33:00 +01:00
parent a4245ed5ce
commit 3bab3cb784
12 changed files with 57 additions and 47 deletions
+16 -8
View File
@@ -12,6 +12,22 @@ HAMQTH_PRG = f"Spothole v{SOFTWARE_VERSION} operated by {SERVER_OWNER_CALLSIGN}"
# Special Interest Groups
SIGS = [
SIG(
name="AMSAT",
comment_names=[],
description="Amateur Radio Satellites",
sig_type=SIGType.WORLDWIDE,
icon="fa-satellite",
refs_globally_unique=False,
),
SIG(
name="EME",
comment_names=[],
description="Moonbounce",
sig_type=SIGType.WORLDWIDE,
icon="fa-moon",
refs_globally_unique=False,
),
SIG(
name="POTA",
comment_names=["POTA"],
@@ -359,14 +375,6 @@ SIGS = [
region_flag="🇵🇱",
refs_globally_unique=False,
),
SIG(
name="AMSAT",
comment_names=[],
description="Amateur Radio Satellites",
sig_type=SIGType.WORLDWIDE,
icon="fa-satellite",
refs_globally_unique=False,
),
SIG(
name="Toilets",
comment_names=[],
+5 -5
View File
@@ -1,7 +1,7 @@
import hashlib
import json
import logging
from dataclasses import dataclass
from dataclasses import dataclass, field
from datetime import datetime, timedelta
import pytz
@@ -64,7 +64,7 @@ class Alert:
# Special Interest Group (SIG), e.g. outdoor activity programme such as POTA
sig: str | None = None
# SIG references. We allow multiple here for e.g. n-fer activations, unlike ADIF SIG_INFO
sig_refs: list | None = None
sig_refs: list = field(default_factory=list)
# Timing info
@@ -128,13 +128,13 @@ class Alert:
# 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:
if self.sig_refs:
for sig_ref in self.sig_refs:
populate_missing_sig_ref_info(sig_ref)
# 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 self.sig_refs[0] and not self.sig:
if self.sig_refs and self.sig_refs[0] and not self.sig:
self.sig = self.sig_refs[0].sig
# Create an ID based on the source and source ID if possible, as these guaranee uniqueness. If there is no
@@ -160,7 +160,7 @@ class Alert:
self.icon = "fa-trophy"
elif self.alert_type == AlertType.CONTEST:
self.icon = "fa-satellite"
elif self.sig_refs and len(self.sig_refs) > 0 and self.sig_refs[0].icon:
elif self.sig_refs and self.sig_refs[0].icon:
self.icon = self.sig_refs[0].icon
except Exception:
+2 -2
View File
@@ -8,10 +8,10 @@ class SIGRef:
"""Data class that defines a Special Interest Group "info" or reference. As well as the basic reference ID we include a
name and a lookup URL."""
# Reference ID, e.g. "GB-0001".
id: str
# SIG that this reference is in, e.g. "POTA".
sig: str
# Reference ID, e.g. "GB-0001".
id: str | None = None
# Name of the reference, e.g. "Null Country Park", if known.
name: str | None = None
# Type of the reference, e.g. "Park", if known.
+19 -17
View File
@@ -2,7 +2,7 @@ import hashlib
import json
import logging
import re
from dataclasses import dataclass
from dataclasses import dataclass, field
from datetime import datetime, timedelta
from math import isnan
@@ -124,7 +124,7 @@ class Spot:
# Special Interest Group (SIG), e.g. outdoor activity programme such as POTA
sig: str | None = None
# SIG references. We allow multiple here for e.g. n-fer activations, unlike ADIF SIG_INFO
sig_refs: list | None = None
sig_refs: list = field(default_factory=list)
# Timing info
@@ -262,12 +262,12 @@ class Spot:
self.dx_location_source = LocationSourceForSpot.SPOT
# Set the top-level "SIG" if it is missing but we have at least one SIG ref.
if not self.sig and self.sig_refs and len(self.sig_refs) > 0:
if not self.sig and self.sig_refs:
self.sig = self.sig_refs[0].sig.upper()
# See if we already have a SIG reference, but the comment looks like it contains more for the same SIG. This
# should catch e.g. POTA comments like "2-fer: GB-0001 GB-0002".
if self.comment and self.sig_refs and len(self.sig_refs) > 0 and self.sig_refs[0].sig:
if self.comment and self.sig_refs and self.sig_refs[0].sig:
sig = self.sig_refs[0].sig.upper()
regex = get_ref_regex_for_sig(sig)
if regex:
@@ -315,7 +315,7 @@ class 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:
if self.sig_refs:
for sig_ref in self.sig_refs:
sig_ref = populate_missing_sig_ref_info(sig_ref)
# If the spot itself doesn't have location yet, but the SIG ref does, extract it
@@ -331,7 +331,7 @@ class Spot:
# 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:
if self.sig_refs and not self.sig:
self.sig = self.sig_refs[0].sig
# Parse "de_grid<prop_mode>dx_grid" structures from the comment, e.g. "JN61ES(ES)JM56XT" or "JO02GQ<>KN17LG".
@@ -359,11 +359,15 @@ class Spot:
self.propagation_mode = mode_tag
logger.info(f"Seen a new propagation mode tag not yet in the system: {mode_tag}")
# Tag satellite contacts as AMSAT SIG
if self.propagation_mode == "Satellite":
if not self.sig:
self.sig = "AMSAT"
self.sig_refs.append(SIGRef(sig="AMSAT"))
# Set SIGs based on propagation mode
if self.propagation_mode == "Satellite":
if not self.sig:
self.sig = "AMSAT"
self.sig_refs.append(SIGRef(sig="AMSAT"))
if self.propagation_mode == "Earth-Moon-Earth":
if not self.sig:
self.sig = "EME"
self.sig_refs.append(SIGRef(sig="EME"))
# Parse "de_grid -> dx_grid" structures from the comment
if self.comment:
@@ -421,7 +425,7 @@ class Spot:
# Determine a "QTH" string. If we have a SIG ref, pick the first one and turn it into a suitable string,
# otherwise see what they have set on an online lookup service.
if self.sig_refs and len(self.sig_refs) > 0:
if self.sig_refs:
qth = self.sig_refs[0].id
if self.sig_refs[0].name:
qth += f" {self.sig_refs[0].name}"
@@ -468,7 +472,7 @@ class Spot:
# Icon for the spot should be the icon of the first SIG ref if present, otherwise a radio tower
self.icon = "fa-tower-cell"
if self.sig_refs and len(self.sig_refs) > 0 and self.sig_refs[0].icon:
if self.sig_refs and self.sig_refs[0].icon:
self.icon = self.sig_refs[0].icon
except Exception:
@@ -482,16 +486,14 @@ class Spot:
def _append_sig_ref_if_missing(self, new_sig_ref):
"""Append a sig_ref to the list, so long as it's not already there."""
sig_refs = self.sig_refs or []
self.sig_refs = sig_refs
new_sig_ref.id = new_sig_ref.id.strip().upper()
new_sig_ref.sig = new_sig_ref.sig.strip().upper()
if new_sig_ref.id == "":
return
for sig_ref in sig_refs:
for sig_ref in self.sig_refs:
if sig_ref.id == new_sig_ref.id and sig_ref.sig == new_sig_ref.sig:
return
sig_refs.append(new_sig_ref)
self.sig_refs.append(new_sig_ref)
def expired(self):
"""Decide if this spot has expired (in which case it should not be added to the system in the first place, and not
+1 -1
View File
@@ -77,7 +77,7 @@
</div>
<script src="/static/js/add-spot.js?v=1789111115"></script>
<script src="/static/js/add-spot.js?v=1789111981"></script>
<script>$(document).ready(function () {
$("#nav-link-add-spot").addClass("active");
}); <!-- highlight active page in nav --></script>
+1 -1
View File
@@ -83,7 +83,7 @@
</div>
<script src="/static/js/alerts.js?v=1789111115"></script>
<script src="/static/js/alerts.js?v=1789111981"></script>
<script>$(document).ready(function () {
$("#nav-link-alerts").addClass("active");
}); <!-- highlight active page in nav --></script>
+2 -2
View File
@@ -76,8 +76,8 @@
</div>
<script src="/static/js/spotsbandsandmap.js?v=1789111115"></script>
<script src="/static/js/bands.js?v=1789111115"></script>
<script src="/static/js/spotsbandsandmap.js?v=1789111981"></script>
<script src="/static/js/bands.js?v=1789111981"></script>
<script>$(document).ready(function () {
$("#nav-link-bands").addClass("active");
}); <!-- highlight active page in nav --></script>
+5 -5
View File
@@ -1,6 +1,6 @@
{% extends "skeleton.html" %}
{% block head_extra %}
<link rel="stylesheet" href="/static/css/style.css?v=1789111115" type="text/css">
<link rel="stylesheet" href="/static/css/style.css?v=1789111980" type="text/css">
<link href="/static/vendor/css/bootstrap-5.3.8.min.css" rel="stylesheet">
<link href="/static/vendor/css/fontawesome-6.7.2.min.css" rel="stylesheet">
<link href="/static/vendor/css/solid-6.7.2.min.css" rel="stylesheet">
@@ -16,10 +16,10 @@
window.fetchEventSource = fetchEventSource;
</script>
<script src="/static/js/utils.js?v=1789111115"></script>
<script src="/static/js/ui-ham.js?v=1789111115"></script>
<script src="/static/js/geo.js?v=1789111115"></script>
<script src="/static/js/common.js?v=1789111115"></script>
<script src="/static/js/utils.js?v=1789111980"></script>
<script src="/static/js/ui-ham.js?v=1789111980"></script>
<script src="/static/js/geo.js?v=1789111980"></script>
<script src="/static/js/common.js?v=1789111980"></script>
{% end %}
{% block body %}
<div class="container">
+1 -1
View File
@@ -284,7 +284,7 @@
</div>
<script src="/static/vendor/js/chart-4.4.9.umd.min.js"></script>
<script src="/static/js/conditions.js?v=1789111115"></script>
<script src="/static/js/conditions.js?v=1789111981"></script>
<script>$(document).ready(function () {
$("#nav-link-conditions").addClass("active");
}); <!-- highlight active page in nav --></script>
+2 -2
View File
@@ -113,8 +113,8 @@
const CARTODB_API_KEY = "{{ web_ui_options.get('cartodb_api_key', '') }}";
</script>
<script src="/static/js/spotsbandsandmap.js?v=1789111115"></script>
<script src="/static/js/map.js?v=1789111115"></script>
<script src="/static/js/spotsbandsandmap.js?v=1789111981"></script>
<script src="/static/js/map.js?v=1789111981"></script>
<script>$(document).ready(function () {
$("#nav-link-map").addClass("active");
}); <!-- highlight active page in nav --></script>
+2 -2
View File
@@ -113,8 +113,8 @@
</div>
<script src="/static/js/spotsbandsandmap.js?v=1789111115"></script>
<script src="/static/js/spots.js?v=1789111115"></script>
<script src="/static/js/spotsbandsandmap.js?v=1789111980"></script>
<script src="/static/js/spots.js?v=1789111980"></script>
<script>$(document).ready(function () {
$("#nav-link-spots").addClass("active");
}); <!-- highlight active page in nav --></script>
+1 -1
View File
@@ -86,7 +86,7 @@
</div>
</div>
<script src="/static/js/status.js?v=1789111115"></script>
<script src="/static/js/status.js?v=1789111981"></script>
<script>
$(document).ready(function () {
$("#nav-link-status").addClass("active");