mirror of
https://git.ianrenton.com/ian/spothole.git
synced 2026-06-24 05:35:10 +00:00
Short/long/closed display for each band calculated from latest data for each ionosonde station
This commit is contained in:
@@ -6,13 +6,14 @@ from threading import Thread, Event
|
||||
import pytz
|
||||
import requests
|
||||
|
||||
from core.constants import HTTP_HEADERS
|
||||
from core.constants import HTTP_HEADERS, BANDS
|
||||
from solarconditionsproviders.solar_conditions_provider import SolarConditionsProvider
|
||||
|
||||
POLL_INTERVAL = 3600 # 1 hour
|
||||
STATIONS_INDEX = "datafiles/didbase-stations.csv"
|
||||
LGDC_URL = "https://lgdc.uml.edu/common/DIDBGetValues"
|
||||
HISTORY_HOURS = 24
|
||||
HF_BANDS = [b for b in BANDS if b.is_ham_hf]
|
||||
|
||||
|
||||
class GIROIonosonde(SolarConditionsProvider):
|
||||
@@ -41,7 +42,8 @@ class GIROIonosonde(SolarConditionsProvider):
|
||||
|
||||
super().setup(solar_conditions, solar_conditions_cache)
|
||||
self.update_data({"ionosonde_data": {
|
||||
s["ursi"]: {"ursi": s["ursi"], "name": s["name"], "fof2": None, "muf": None, "luf": None}
|
||||
s["ursi"]: {"ursi": s["ursi"], "name": s["name"], "fof2": None, "muf": None, "luf": None,
|
||||
"band_states": None}
|
||||
for s in self._stations
|
||||
}})
|
||||
|
||||
@@ -75,7 +77,9 @@ class GIROIonosonde(SolarConditionsProvider):
|
||||
try:
|
||||
fof2, muf, luf = self._fetch_station_data(ursi, from_time, now)
|
||||
if fof2 and muf:
|
||||
ionosonde_data[ursi] = {"ursi": ursi, "name": name, "fof2": fof2, "muf": muf, "luf": luf or None}
|
||||
band_states = self._compute_band_statess(fof2, muf, luf or {})
|
||||
ionosonde_data[ursi] = {"ursi": ursi, "name": name, "fof2": fof2, "muf": muf,
|
||||
"luf": luf or None, "band_states": band_states}
|
||||
updated_count += 1
|
||||
except Exception:
|
||||
logging.warning(f"Could not fetch ionosonde data for {ursi} ({name})")
|
||||
@@ -101,6 +105,40 @@ class GIROIonosonde(SolarConditionsProvider):
|
||||
return None, None, None
|
||||
return self._parse_all(response.text)
|
||||
|
||||
@staticmethod
|
||||
def _latest(d):
|
||||
"""Return the value with the highest timestamp key, or None if the dict is empty."""
|
||||
return d[max(d.keys())] if d else None
|
||||
|
||||
@staticmethod
|
||||
def _compute_band_statess(fof2_dict, muf_dict, luf_dict):
|
||||
"""Compute HF band states from the latest foF2, MUF and LUF values.
|
||||
|
||||
States:
|
||||
Closed if band frequency is below LUF (if known) or above MUF
|
||||
Short if band frequency is >= LUF and < foF2 (good for NVIS)
|
||||
Long if band frequency is >= foF2 and < MUF (good for DX)
|
||||
"""
|
||||
|
||||
# We have a list of timestamped data for each value, but for this we only want the latest value
|
||||
fof2 = GIROIonosonde._latest(fof2_dict)
|
||||
muf = GIROIonosonde._latest(muf_dict)
|
||||
luf = GIROIonosonde._latest(luf_dict)
|
||||
if fof2 is None or muf is None:
|
||||
return {}
|
||||
band_states = {}
|
||||
|
||||
# Iterate over all ham HF bands, we don't care about the others at this point
|
||||
for band in HF_BANDS:
|
||||
freq = band.start_freq / 1000000
|
||||
if freq > muf or (luf is not None and freq < luf):
|
||||
band_states[band.name] = "Closed"
|
||||
elif freq < fof2:
|
||||
band_states[band.name] = "Short"
|
||||
else:
|
||||
band_states[band.name] = "Long"
|
||||
return band_states
|
||||
|
||||
@staticmethod
|
||||
def _parse_all(text):
|
||||
"""Parse web server response and return (fof2_dict, muf_dict, luf_dict) keyed by UNIX timestamp."""
|
||||
|
||||
Reference in New Issue
Block a user