mirror of
https://git.ianrenton.com/ian/spothole.git
synced 2026-09-20 06:17:41 +00:00
86 lines
3.0 KiB
Python
86 lines
3.0 KiB
Python
import logging
|
|
from datetime import datetime
|
|
from threading import Event, Thread
|
|
|
|
import aprslib
|
|
import pytz
|
|
|
|
from core.config import SERVER_OWNER_CALLSIGN
|
|
from data.spot import Spot
|
|
from providers.spot.spot_provider import SpotProvider
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class APRSIS(SpotProvider):
|
|
"""Spot provider for the APRS-IS."""
|
|
|
|
def __init__(self, provider_config):
|
|
super().__init__("APRS-IS", provider_config)
|
|
self._thread = None
|
|
self._aprsis = None
|
|
self._stop_event = Event()
|
|
|
|
def start(self):
|
|
self._thread = Thread(target=self._run, name="APRSISSpotProvider", daemon=True)
|
|
self._thread.start()
|
|
|
|
def _run(self):
|
|
while not self._stop_event.is_set():
|
|
try:
|
|
self._aprsis = aprslib.IS(SERVER_OWNER_CALLSIGN)
|
|
self.status = "Connecting"
|
|
logger.info("APRS-IS connecting...")
|
|
self._aprsis.connect()
|
|
logger.info("APRS-IS connected.")
|
|
self._aprsis.consumer(self._handle, immortal=True)
|
|
|
|
except Exception:
|
|
if not self._stop_event.is_set():
|
|
self.status = "Error"
|
|
logger.exception("Exception in APRS-IS provider")
|
|
|
|
if not self._stop_event.is_set():
|
|
self._stop_event.wait(timeout=5)
|
|
|
|
def stop(self):
|
|
self.status = "Shutting down"
|
|
self._stop_event.set()
|
|
if self._aprsis:
|
|
self._aprsis.close()
|
|
if self._thread:
|
|
self._thread.join(timeout=15)
|
|
if self._thread.is_alive():
|
|
logger.warning("APRS-IS worker thread did not exit on time and will be killed.")
|
|
|
|
def _handle(self, data):
|
|
try:
|
|
# Split SSID in "from" call and store separately
|
|
from_parts = str(data["from"]).split("-")
|
|
dx_call = from_parts[0].upper()
|
|
dx_ssid = from_parts[1].upper() if len(from_parts) > 1 else None
|
|
via_parts = str(data["via"]).split("-")
|
|
de_call = via_parts[0].upper()
|
|
de_ssid = via_parts[1].upper() if len(via_parts) > 1 else None
|
|
spot = Spot(
|
|
source="APRS-IS",
|
|
dx_call=dx_call,
|
|
dx_ssid=dx_ssid,
|
|
de_call=de_call,
|
|
de_ssid=de_ssid,
|
|
comment=str(data["comment"]) if "comment" in data else None,
|
|
dx_latitude=float(data["latitude"]) if data.get("latitude") is not None else None,
|
|
dx_longitude=float(data["longitude"]) if data.get("longitude") is not None else None,
|
|
time=datetime.now(pytz.UTC).timestamp(),
|
|
) # APRS-IS spots are live so we can assume spot time is "now"
|
|
|
|
# Add to our list
|
|
self._submit(spot)
|
|
|
|
self.status = "OK"
|
|
self.last_update_time = datetime.now(pytz.UTC)
|
|
logger.debug("Data received from APRS-IS.")
|
|
|
|
except Exception:
|
|
logger.exception("Exception handling APRS-IS packet")
|