-
-
SFI
-
{spaceWeather.data?.solarFlux || '--'}
-
-
-
K-Index
-
4 ? 'var(--accent-red)' : 'var(--accent-green)', fontWeight: '700' }}>{spaceWeather.data?.kIndex || '-'}
-
-
-
SSN
-
{spaceWeather.data?.sunspotNumber || '--'}
+ {/* TOP RIGHT - Solar Indices with Mini Charts */}
+
+
☀ SOLAR INDICES
+ {solarIndices.data ? (
+
+ {/* SFI */}
+
+
SFI
+
+ {solarIndices.data.sfi?.current || '--'}
+
+ {solarIndices.data.sfi?.history?.length > 0 && (
+
+ )}
+
+ {/* SSN */}
+
+
SSN
+
+ {solarIndices.data.ssn?.current || '--'}
+
+ {solarIndices.data.ssn?.history?.length > 0 && (
+
+ )}
+
+ {/* Kp */}
+
+
Kp
+
= 5 ? '#ff6600' : solarIndices.data.kp?.current >= 4 ? '#ffcc00' : '#00ff88'
+ }}>
+ {solarIndices.data.kp?.current?.toFixed(1) || '--'}
+
+ {solarIndices.data.kp?.history?.length > 0 && (
+
+ )}
+
-
-
Conditions
-
{spaceWeather.data?.conditions || '--'}
+ ) : (
+
+
+
SFI
+
{spaceWeather.data?.solarFlux || '--'}
+
+
+
Kp
+
4 ? 'var(--accent-red)' : 'var(--accent-green)', fontWeight: '700' }}>{spaceWeather.data?.kIndex || '-'}
+
-
+ )}
{/* LEFT SIDEBAR - DE/DX Info */}
@@ -3192,6 +3492,7 @@
const spaceWeather = useSpaceWeather();
const bandConditions = useBandConditions(spaceWeather.data);
+ const solarIndices = useSolarIndices();
const potaSpots = usePOTASpots();
const dxCluster = useDXCluster(config.dxClusterSource || 'auto');
const dxPaths = useDXPaths();
@@ -3271,6 +3572,7 @@
onDXChange={handleDXChange}
spaceWeather={spaceWeather}
bandConditions={bandConditions}
+ solarIndices={solarIndices}
potaSpots={potaSpots}
dxCluster={dxCluster}
dxPaths={dxPaths}
@@ -3466,6 +3768,9 @@
{/* VOACAP Propagation - Toggleable */}
+
+ {/* Solar Indices with History */}
+
{/* CENTER - MAP */}
diff --git a/server.js b/server.js
index 7f2e4b0..2d07df9 100644
--- a/server.js
+++ b/server.js
@@ -67,6 +67,84 @@ app.get('/api/noaa/sunspots', async (req, res) => {
}
});
+// Solar Indices with History and Kp Forecast
+app.get('/api/solar-indices', async (req, res) => {
+ try {
+ const [fluxRes, kIndexRes, kForecastRes, sunspotRes] = await Promise.allSettled([
+ fetch('https://services.swpc.noaa.gov/json/f107_cm_flux.json'),
+ fetch('https://services.swpc.noaa.gov/products/noaa-planetary-k-index.json'),
+ fetch('https://services.swpc.noaa.gov/products/noaa-planetary-k-index-forecast.json'),
+ fetch('https://services.swpc.noaa.gov/json/solar-cycle/observed-solar-cycle-indices.json')
+ ]);
+
+ const result = {
+ sfi: { current: null, history: [] },
+ kp: { current: null, history: [], forecast: [] },
+ ssn: { current: null, history: [] },
+ timestamp: new Date().toISOString()
+ };
+
+ // Process SFI data (last 30 days)
+ if (fluxRes.status === 'fulfilled' && fluxRes.value.ok) {
+ const data = await fluxRes.value.json();
+ if (data?.length) {
+ // Get last 30 entries
+ const recent = data.slice(-30);
+ result.sfi.history = recent.map(d => ({
+ date: d.time_tag || d.date,
+ value: Math.round(d.flux || d.value || 0)
+ }));
+ result.sfi.current = result.sfi.history[result.sfi.history.length - 1]?.value || null;
+ }
+ }
+
+ // Process Kp history (last 3 days, data comes in 3-hour intervals)
+ if (kIndexRes.status === 'fulfilled' && kIndexRes.value.ok) {
+ const data = await kIndexRes.value.json();
+ if (data?.length > 1) {
+ // Skip header row, get last 24 entries (3 days)
+ const recent = data.slice(1).slice(-24);
+ result.kp.history = recent.map(d => ({
+ time: d[0],
+ value: parseFloat(d[1]) || 0
+ }));
+ result.kp.current = result.kp.history[result.kp.history.length - 1]?.value || null;
+ }
+ }
+
+ // Process Kp forecast
+ if (kForecastRes.status === 'fulfilled' && kForecastRes.value.ok) {
+ const data = await kForecastRes.value.json();
+ if (data?.length > 1) {
+ // Skip header row
+ result.kp.forecast = data.slice(1).map(d => ({
+ time: d[0],
+ value: parseFloat(d[1]) || 0
+ }));
+ }
+ }
+
+ // Process Sunspot data (last 12 months)
+ if (sunspotRes.status === 'fulfilled' && sunspotRes.value.ok) {
+ const data = await sunspotRes.value.json();
+ if (data?.length) {
+ // Get last 12 entries (monthly data)
+ const recent = data.slice(-12);
+ result.ssn.history = recent.map(d => ({
+ date: `${d['time-tag'] || d.time_tag || ''}`,
+ value: Math.round(d.ssn || 0)
+ }));
+ result.ssn.current = result.ssn.history[result.ssn.history.length - 1]?.value || null;
+ }
+ }
+
+ res.json(result);
+ } catch (error) {
+ console.error('Solar Indices API error:', error.message);
+ res.status(500).json({ error: 'Failed to fetch solar indices' });
+ }
+});
+
// NOAA Space Weather - X-Ray Flux
app.get('/api/noaa/xray', async (req, res) => {
try {