mirror of
https://git.ianrenton.com/ian/spothole.git
synced 2025-10-27 08:49:27 +00:00
DX Cluster support
This commit is contained in:
@@ -3,6 +3,7 @@ from data.band import Band
|
|||||||
# General software
|
# General software
|
||||||
SOFTWARE_NAME = "Metaspot by M0TRT"
|
SOFTWARE_NAME = "Metaspot by M0TRT"
|
||||||
SOFTWARE_VERSION = "0.1"
|
SOFTWARE_VERSION = "0.1"
|
||||||
|
SERVER_OWNER_CALLSIGN = "M0TRT"
|
||||||
|
|
||||||
# Band definitions
|
# Band definitions
|
||||||
BANDS = [
|
BANDS = [
|
||||||
|
|||||||
14
data/spot.py
14
data/spot.py
@@ -1,6 +1,8 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
from pyhamtools.locator import locator_to_latlong, latlong_to_locator
|
||||||
|
|
||||||
from core.constants import DXCC_FLAGS
|
from core.constants import DXCC_FLAGS
|
||||||
from core.utils import infer_mode_family_from_mode, infer_band_from_freq, infer_continent_from_callsign, \
|
from core.utils import infer_mode_family_from_mode, infer_band_from_freq, infer_continent_from_callsign, \
|
||||||
infer_country_from_callsign, infer_cq_zone_from_callsign, infer_itu_zone_from_callsign, infer_dxcc_id_from_callsign
|
infer_country_from_callsign, infer_cq_zone_from_callsign, infer_itu_zone_from_callsign, infer_dxcc_id_from_callsign
|
||||||
@@ -97,4 +99,14 @@ class Spot:
|
|||||||
self.band_contrast_color = band.contrast_color
|
self.band_contrast_color = band.contrast_color
|
||||||
|
|
||||||
if self.mode and not self.mode_family:
|
if self.mode and not self.mode_family:
|
||||||
self.mode_family=infer_mode_family_from_mode(self.mode)
|
self.mode_family=infer_mode_family_from_mode(self.mode)
|
||||||
|
|
||||||
|
if self.grid and not self.latitude:
|
||||||
|
ll = locator_to_latlong(self.grid)
|
||||||
|
self.latitude = ll[0]
|
||||||
|
self.longitude = ll[1]
|
||||||
|
|
||||||
|
if self.latitude and self.longitude and not self.grid:
|
||||||
|
self.grid = latlong_to_locator(self.latitude, self.longitude, 8)
|
||||||
|
|
||||||
|
# TODO lat/lon from DXCC centre?
|
||||||
9
main.py
9
main.py
@@ -2,6 +2,7 @@
|
|||||||
import signal
|
import signal
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
|
from providers.dxcluster import DXCluster
|
||||||
from providers.pota import POTA
|
from providers.pota import POTA
|
||||||
|
|
||||||
|
|
||||||
@@ -17,7 +18,10 @@ if __name__ == '__main__':
|
|||||||
signal.signal(signal.SIGINT, shutdown)
|
signal.signal(signal.SIGINT, shutdown)
|
||||||
|
|
||||||
# Create providers
|
# Create providers
|
||||||
providers = [POTA()] # todo all other providers
|
providers = [
|
||||||
|
POTA(),
|
||||||
|
DXCluster("hrd.wa9pie.net", 8000)
|
||||||
|
] # todo all other providers
|
||||||
# Set up spot list
|
# Set up spot list
|
||||||
spot_list = []
|
spot_list = []
|
||||||
# Set up data providers
|
# Set up data providers
|
||||||
@@ -32,9 +36,6 @@ if __name__ == '__main__':
|
|||||||
# Todo serve apidocs
|
# Todo serve apidocs
|
||||||
# Todo serve website
|
# Todo serve website
|
||||||
|
|
||||||
sleep(2)
|
|
||||||
print(len(spot_list))
|
|
||||||
print(spot_list[0])
|
|
||||||
|
|
||||||
|
|
||||||
# NOTES FOR FIELD SPOTTER
|
# NOTES FOR FIELD SPOTTER
|
||||||
|
|||||||
65
providers/dxcluster.py
Normal file
65
providers/dxcluster.py
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
from datetime import datetime, timezone
|
||||||
|
from threading import Thread
|
||||||
|
|
||||||
|
import pytz
|
||||||
|
|
||||||
|
from core.constants import SERVER_OWNER_CALLSIGN
|
||||||
|
from data.spot import Spot
|
||||||
|
from providers.provider import Provider
|
||||||
|
import telnetlib3
|
||||||
|
import re
|
||||||
|
|
||||||
|
callsign_pattern = "([a-z|0-9|/]+)"
|
||||||
|
frequency_pattern = "([0-9|.]+)"
|
||||||
|
pattern = re.compile("^DX de "+callsign_pattern+":\\s+"+frequency_pattern+"\\s+"+callsign_pattern+"\\s+(.*)\\s+(\\d{4}Z)", re.IGNORECASE)
|
||||||
|
|
||||||
|
class DXCluster(Provider):
|
||||||
|
|
||||||
|
# Constructor requires hostname and port
|
||||||
|
def __init__(self, hostname, port):
|
||||||
|
super().__init__()
|
||||||
|
self.hostname = hostname
|
||||||
|
self.port = port
|
||||||
|
self.telnet = None
|
||||||
|
self.thread = None
|
||||||
|
self.run = True
|
||||||
|
|
||||||
|
def name(self):
|
||||||
|
return "DX Cluster " + self.hostname + " " + str(self.port)
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.thread = Thread(target=self.handle)
|
||||||
|
self.thread.start()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.run = False
|
||||||
|
self.telnet.close()
|
||||||
|
self.thread.join()
|
||||||
|
|
||||||
|
def handle(self):
|
||||||
|
self.status = "Connecting"
|
||||||
|
self.telnet = telnetlib3.Telnet(self.hostname, self.port)
|
||||||
|
self.telnet.read_until("login: ".encode("ascii"))
|
||||||
|
self.telnet.write((SERVER_OWNER_CALLSIGN + "\n").encode("ascii"))
|
||||||
|
self.status = "Waiting for Data"
|
||||||
|
|
||||||
|
while self.run:
|
||||||
|
# Check new telnet info against regular expression
|
||||||
|
telnet_output = self.telnet.read_until("\n".encode("ascii"))
|
||||||
|
match = pattern.match(telnet_output.decode("ascii"))
|
||||||
|
if match:
|
||||||
|
spot_time = datetime.strptime(match.group(5), "%H%MZ")
|
||||||
|
spot_datetime = datetime.combine(datetime.today(), spot_time.time()).replace(tzinfo=pytz.UTC)
|
||||||
|
spot = Spot(source=self.name(),
|
||||||
|
dx_call=match.group(3),
|
||||||
|
de_call=match.group(1),
|
||||||
|
freq=float(match.group(2)),
|
||||||
|
comment=match.group(4).strip(),
|
||||||
|
time=spot_datetime)
|
||||||
|
# Fill in any blanks
|
||||||
|
spot.infer_missing()
|
||||||
|
# Add to our list
|
||||||
|
self.submit([spot])
|
||||||
|
|
||||||
|
self.status = "OK"
|
||||||
|
self.last_update_time = datetime.now(timezone.utc)
|
||||||
@@ -31,7 +31,7 @@ class POTA(Provider):
|
|||||||
# Iterate through source data
|
# Iterate through source data
|
||||||
for source_spot in source_data:
|
for source_spot in source_data:
|
||||||
# Convert to our spot format
|
# Convert to our spot format
|
||||||
spot = Spot(source="POTA",
|
spot = Spot(source=self.name(),
|
||||||
source_id=source_spot["spotId"],
|
source_id=source_spot["spotId"],
|
||||||
dx_call=source_spot["activator"],
|
dx_call=source_spot["activator"],
|
||||||
de_call=source_spot["spotter"],
|
de_call=source_spot["spotter"],
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
pytz
|
||||||
requests~=2.32.5
|
requests~=2.32.5
|
||||||
Reference in New Issue
Block a user