Improve the way hamsat alerts work, and add the ability to detect satellite names from spot comments. Closes #149

This commit is contained in:
Ian Renton
2026-09-23 22:08:36 +01:00
parent 981fea57ed
commit c26482f06b
15 changed files with 90 additions and 35 deletions
+34 -6
View File
@@ -5,6 +5,7 @@ from dataclasses import dataclass, field
from datetime import datetime, timedelta
import pytz
from pyhamtools.locator import locator_to_latlong, latlong_to_locator
from core.activity_lookup_helper import populate_missing_activity_ref_info
from core.activity_utils import get_icon_for_activity
@@ -40,6 +41,11 @@ class Alert:
dx_cq_zone: int | None = None
# ITU zone of the DX operator
dx_itu_zone: int | None = None
# Maidenhead grid locator for the DX. This could be from a geographical reference e.g. POTA or grid.
dx_grid: str | None = None
# Latitude & longitude of the DX, in degrees. This could be from a geographical reference e.g. POTA or grid.
dx_latitude: float | None = None
dx_longitude: float | None = None
# General alert info
@@ -108,8 +114,7 @@ class Alert:
if self.received_time and not self.received_time_iso:
self.received_time_iso = datetime.fromtimestamp(self.received_time, pytz.UTC).isoformat()
# DX country, continent, zones etc. from callsign. CQ/ITU zone are better looked up with a location but we don't
# have a real location for alerts.
# DX country, continent, zones etc. from callsign.
if self.dx_calls and self.dx_calls[0]:
call_info = get_call_info(self.dx_calls[0], credentials)
if self.dx_calls and self.dx_calls[0] and not self.dx_country:
@@ -125,18 +130,41 @@ class Alert:
if self.dx_dxcc_id and not self.dx_flag:
self.dx_flag = get_flag_for_dxcc(self.dx_dxcc_id)
# Fetch activity 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 an activity even though there's no real lookup, just maths
# Fetch activity data, and set a real position if we can get one.
if self.sig_refs:
for activity_ref in self.sig_refs:
populate_missing_activity_ref_info(activity_ref)
activity_ref = populate_missing_activity_ref_info(activity_ref)
# If the alert itself doesn't have location yet, but the activity ref does, extract it
if activity_ref.grid and not self.dx_grid:
self.dx_grid = activity_ref.grid
if (
activity_ref.latitude
and not self.dx_latitude
and activity_ref.longitude
and not self.dx_longitude
):
self.dx_latitude = activity_ref.latitude
self.dx_longitude = activity_ref.longitude
# If the spot itself doesn't have an activity yet, but we have at least one activity reference, take that
# reference's activity and apply it to the whole spot.
if self.sig_refs and self.sig_refs[0] and not self.sig:
self.sig = self.sig_refs[0].sig
# DX Grid to lat/lon and vice versa in case one is missing
if self.dx_grid and (not self.dx_latitude or not self.dx_longitude):
try:
ll = locator_to_latlong(self.dx_grid)
self.dx_latitude = ll[0]
self.dx_longitude = ll[1]
except Exception:
logger.debug("Invalid grid received for spot", exc_info=True)
if self.dx_latitude and self.dx_longitude and not self.dx_grid:
try:
self.dx_grid = latlong_to_locator(self.dx_latitude, self.dx_longitude, 8)
except Exception:
logger.debug("Invalid lat/lon received for spot", exc_info=True)
# Create an ID based on the source and source ID if possible, as these guaranee uniqueness. If there is no
# source ID, use a combination of callsign and start time. Excluding things like the comment here allows for
# user updates of their alert comments without duplicating in the system.