diff --git a/README.md b/README.md index a4e41ba..5c46d8e 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,7 @@ To navigate your way around the source code, this list may help. * `/` - Main script (`spothole.py`), pip `requirements.txt`, config, README, etc. * `/images` - Image sources +* `/datafiles` - Local data sources (differentiated from the majority of data files which are loaded from URLs and cached in `/cache`) * `/cache` - Directory where static-ish data downloaded from the internet is cached to avoid rapid re-requests, and where spot/alert data is cached so that it survives a software restart. Created on first run. ### Extending the server diff --git a/config-example.yml b/config-example.yml index db8270e..fb72cb6 100644 --- a/config-example.yml +++ b/config-example.yml @@ -86,12 +86,11 @@ spot-providers: name: "39C3 TOTA" enabled: false url: "wss://dev.39c3.totawatch.de/api/spot/live" - # Fixed SIG/latitude/longitude for all spots from a provider is currently only a feature for the "XOTA" provider, + # Fixed SIG for all spots from a provider & location CSV are currently only a feature for the "XOTA" provider, # the software found at https://github.com/nischu/xOTA/. This is because this is a generic backend for xOTA # programmes and so different URLs provide different programmes. sig: "TOTA" - latitude: 53.5622678 - longitude: 9.9855205 + locations-csv: "datafiles/39c3-tota.csv" # Alert providers to use. Same setup as the spot providers list above. diff --git a/datafiles/39c3-tota.csv b/datafiles/39c3-tota.csv new file mode 100644 index 0000000..15f6ac6 --- /dev/null +++ b/datafiles/39c3-tota.csv @@ -0,0 +1,18 @@ +ref,lat,lon +T-01,53.56278090617755,9.984341869295505 +T-02,53.562383404176416,9.98551893027115 +T-03,53.56170184391514,9.985416035619778 +T-04,53.562026534393176,9.986372919078974 +T-11,53.56284641242506,9.98475590239655 +T-12,53.562431705517035,9.98551675702443 +T-13,53.56223704898424,9.985774520335664 +T-14,53.5617893512591,9.986344302837976 +T-21,53.56284641242506,9.98475590239655 +T-22,53.56245816412497,9.985456089490567 +T-23,53.56199560857136,9.985636761412673 +T-24,53.5617893512591,9.986344302837976 +T-31,53.56247470064887,9.985611427551902 +T-32,53.5617893512591,9.986344302837976 +T-41,53.56245039134992,9.985486136112701 +T-91,53.56147934973529,9.984626806439744 +T-92,53.561396810300735,9.987553052152899 \ No newline at end of file diff --git a/spotproviders/xota.py b/spotproviders/xota.py index da04a0d..b6fbfc6 100644 --- a/spotproviders/xota.py +++ b/spotproviders/xota.py @@ -1,4 +1,6 @@ +import csv import json +import logging from datetime import datetime import pytz @@ -9,31 +11,45 @@ from spotproviders.websocket_spot_provider import WebsocketSpotProvider # Spot provider for servers based on the "xOTA" software at https://github.com/nischu/xOTA/ -# The provider typically doesn't give us a lat/lon or SIG explicitly, so our own config provides this information. This -# functionality is implemented for TOTA events. +# The provider typically doesn't give us a lat/lon or SIG explicitly, so our own config provides a SIG and a reference +# to a local CSV file with location information. This functionality is implemented for TOTA events, of which there are +# several - so a plain lookup of a "TOTA reference" doesn't make sense, it depends on which TOTA and hence which server +# supplied the data, which is why the CSV location lookup is here and not in sig_utils. class XOTA(WebsocketSpotProvider): - FIXED_LATITUDE = None - FIXED_LONGITUDE = None + LOCATION_DATA = {} SIG = None def __init__(self, provider_config): super().__init__(provider_config, provider_config["url"]) - self.FIXED_LATITUDE = provider_config["latitude"] if "latitude" in provider_config else None - self.FIXED_LONGITUDE = provider_config["longitude"] if "longitude" in provider_config else None + locations_csv = provider_config["locations-csv"] if "locations-csv" in provider_config else None self.SIG = provider_config["sig"] if "sig" in provider_config else None + # Load location data + if locations_csv: + try: + f = open(locations_csv) + csv_data = f.read() + dr = csv.DictReader(csv_data.splitlines()) + for row in dr: + self.LOCATION_DATA[row["ref"]] = {"lat": row["lat"], "lon": row["lon"]} + except: + logging.exception("Could not look up location data for XOTA source.") + def ws_message_to_spot(self, bytes): string = bytes.decode("utf-8") source_spot = json.loads(string) + ref_id = source_spot["reference"]["title"] + lat = float(self.LOCATION_DATA[ref_id]["lat"]) if ref_id in self.LOCATION_DATA else None + lon = float(self.LOCATION_DATA[ref_id]["lon"]) if ref_id in self.LOCATION_DATA else None spot = Spot(source=self.name, source_id=source_spot["id"], dx_call=source_spot["stationCallSign"].upper(), freq=float(source_spot["freq"]) * 1000, mode=source_spot["mode"].upper(), sig=self.SIG, - sig_refs=[SIGRef(id=source_spot["reference"]["title"], sig=self.SIG, url=source_spot["reference"]["website"])], + sig_refs=[SIGRef(id=ref_id, sig=self.SIG, url=source_spot["reference"]["website"], latitude=lat, longitude=lon)], time=datetime.now(pytz.UTC).timestamp(), - dx_latitude=self.FIXED_LATITUDE, - dx_longitude=self.FIXED_LONGITUDE, + dx_latitude=lat, + dx_longitude=lon, qrt=source_spot["state"] != "active") return spot