diff --git a/solarconditionsproviders/giroionosonde.py b/solarconditionsproviders/giroionosonde.py
index b15c54d..4f5b6c6 100644
--- a/solarconditionsproviders/giroionosonde.py
+++ b/solarconditionsproviders/giroionosonde.py
@@ -35,6 +35,16 @@ class GIROIonosonde(SolarConditionsProvider):
stations.append({"ursi": row[0].strip(), "name": row[1].strip()})
return stations
+ def setup(self, solar_conditions, solar_conditions_cache):
+ """Prepopulate the ionosonde_data map with known URSI and station names, so that the API exposes this structure
+ even before we actually have any data in it."""
+
+ super().setup(solar_conditions, solar_conditions_cache)
+ self.update_data({"ionosonde_data": {
+ s["ursi"]: {"ursi": s["ursi"], "name": s["name"], "fof2": None, "muf": None}
+ for s in self._stations
+ }})
+
def start(self):
logging.info(f"Set up query of GIRO ionosonde data API every {POLL_INTERVAL} seconds.")
self._thread = Thread(target=self._run, daemon=True)
diff --git a/templates/about.html b/templates/about.html
index 165ed88..493ff96 100644
--- a/templates/about.html
+++ b/templates/about.html
@@ -69,7 +69,7 @@
This software is dedicated to the memory of Tom G1PJB, SK, a friend and colleague who sadly passed away around the time I started writing it in Autumn 2025. I was looking forward to showing it to you when it was done.
-
+
{% end %}
\ No newline at end of file
diff --git a/templates/add_spot.html b/templates/add_spot.html
index 95964dd..d427bd2 100644
--- a/templates/add_spot.html
+++ b/templates/add_spot.html
@@ -69,8 +69,8 @@
-
-
+
+
{% end %}
\ No newline at end of file
diff --git a/templates/alerts.html b/templates/alerts.html
index 076c652..1e6a312 100644
--- a/templates/alerts.html
+++ b/templates/alerts.html
@@ -70,8 +70,8 @@
-
-
+
+
{% end %}
\ No newline at end of file
diff --git a/templates/bands.html b/templates/bands.html
index c56e993..6c3db4d 100644
--- a/templates/bands.html
+++ b/templates/bands.html
@@ -76,9 +76,9 @@
-
-
-
+
+
+
{% end %}
\ No newline at end of file
diff --git a/templates/base.html b/templates/base.html
index 5a57e3e..f43b23e 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -24,7 +24,7 @@
Spothole
-
+
@@ -52,9 +52,9 @@
integrity="sha384-L1eE4eD41kpBIWe2I0eHy+GnEUC4RIpcvibVW2JCminuPlTl+2Bc528iPdVMg5Dn"
crossorigin="anonymous">
-
-
-
+
+
+
diff --git a/templates/conditions.html b/templates/conditions.html
index 69814ec..35493cf 100644
--- a/templates/conditions.html
+++ b/templates/conditions.html
@@ -176,7 +176,7 @@
{% if has_giro_ionosonde %}
- Critical & Maximum Usable Frequencies
+ Ionosonde Data
@@ -249,8 +249,8 @@
-
-
+
+
diff --git a/templates/map.html b/templates/map.html
index d7800fc..affb7fd 100644
--- a/templates/map.html
+++ b/templates/map.html
@@ -94,9 +94,9 @@
-
-
-
+
+
+
{% end %}
\ No newline at end of file
diff --git a/templates/spots.html b/templates/spots.html
index 8af4444..8c26a2b 100644
--- a/templates/spots.html
+++ b/templates/spots.html
@@ -104,9 +104,9 @@
-
-
-
+
+
+
{% end %}
\ No newline at end of file
diff --git a/templates/status.html b/templates/status.html
index e2fc24e..86257bd 100644
--- a/templates/status.html
+++ b/templates/status.html
@@ -59,8 +59,8 @@
-
-
+
+
diff --git a/webassets/apidocs/openapi.yml b/webassets/apidocs/openapi.yml
index 2603407..9dd75cf 100644
--- a/webassets/apidocs/openapi.yml
+++ b/webassets/apidocs/openapi.yml
@@ -1691,9 +1691,8 @@ components:
type: object
nullable: true
description: >
- Ionosonde measurements from the GIRO Data Center, keyed by URSI station code. Only
- stations for which data was successfully retrieved are included. Null if the
- GIROIonosonde provider has not yet completed its first poll or if this data source is disabled.
+ Ionosonde measurements from the GIRO Data Center, keyed by URSI station code. All known stations are
+ included, but not all of them may contain data.
additionalProperties:
$ref: '#/components/schemas/IonosondeStation'
@@ -1712,7 +1711,7 @@ components:
fof2:
type: object
nullable: true
- description: F2 layer critical frequency (foF2) measurements in MHz, keyed by UNIX timestamp (UTC seconds since epoch) of each measurement.
+ description: F2 layer critical frequency (foF2) measurements in MHz, keyed by UNIX timestamp (UTC seconds since epoch) of each measurement. Can be null if there is no data.
additionalProperties:
type: number
example:
@@ -1721,7 +1720,7 @@ components:
muf:
type: object
nullable: true
- description: Maximum Usable Frequency (MUF) for a 3000 km path in MHz, keyed by UNIX timestamp (UTC seconds since epoch) of each measurement.
+ description: Maximum Usable Frequency (MUF) for a 3000 km path in MHz, keyed by UNIX timestamp (UTC seconds since epoch) of each measurement. Can be null if there is no data.
additionalProperties:
type: number
example:
diff --git a/webassets/js/conditions.js b/webassets/js/conditions.js
index 948c6ec..d5dab24 100644
--- a/webassets/js/conditions.js
+++ b/webassets/js/conditions.js
@@ -380,7 +380,9 @@ function populateIonosondeDropdown(data) {
// Render the foF2/MUF data and line chart for the currently selected station
function renderIonosondeData() {
// First make sure that we have some data, that a station entry is selected in the drop-down box, and that the
- // data contains an entry for that station. If not, bail out at this point.
+ // data contains an entry for that station. If not, this represents an odd state (over and above just "no data for
+ // this station", so bail out at this point. The user will have to reselect something from the list, or wait until
+ // the API is behaving itself again.
if (!ionosondeData) return;
const ursi = $('#ionosonde-station').val();
if (!ursi) return;
@@ -406,7 +408,12 @@ function renderIonosondeData() {
const fof2Entries = toSeries(station.fof2);
const mufEntries = toSeries(station.muf);
const allTs = [...fof2Entries, ...mufEntries].map(e => e.ts);
- if (allTs.length === 0) return;
+ if (allTs.length === 0) {
+ $('#ionosonde-latest').html('
' +
+ staleWarning +
''
);
@@ -564,6 +575,9 @@ function renderIonosondeData() {
},
plugins: [bandLinesPlugin],
});
+
+ // Chart canvas is normally hidden until we get here with some definitely good data. Now we have that so show it
+ $('#ionosonde-chart').show();
}
// Called when the ionosonde station select changes