From 4e8134e44d019bb240e022455413981340db629e Mon Sep 17 00:00:00 2001 From: accius Date: Sat, 31 Jan 2026 15:31:24 -0500 Subject: [PATCH] Add DX Cluster source selection with DX Spider telnet support --- public/index.html | 68 +++++++-- server.js | 381 ++++++++++++++++++++++++++++++++-------------- setup-pi.sh | 194 ----------------------- 3 files changed, 319 insertions(+), 324 deletions(-) delete mode 100644 setup-pi.sh diff --git a/public/index.html b/public/index.html index 72995f5..538a8ba 100644 --- a/public/index.html +++ b/public/index.html @@ -668,25 +668,31 @@ return { data, loading }; }; - const useDXCluster = () => { + const useDXCluster = (source = 'auto') => { const [data, setData] = useState([]); const [loading, setLoading] = useState(true); + const [activeSource, setActiveSource] = useState(''); useEffect(() => { const fetchDX = async () => { try { - // Use our proxy endpoint (works when running via server.js) - const response = await fetch('/api/dxcluster/spots'); + // Use our proxy endpoint with source parameter + const response = await fetch(`/api/dxcluster/spots?source=${source}`); if (response.ok) { const spots = await response.json(); if (spots && spots.length > 0) { + // Track the active source from the first spot + if (spots[0].source) { + setActiveSource(spots[0].source); + } setData(spots.slice(0, 15).map(s => ({ freq: s.freq || (s.frequency ? (parseFloat(s.frequency) / 1000).toFixed(3) : '0.000'), call: s.call || s.dx_call || 'UNKNOWN', comment: s.comment || s.info || '', time: s.time || new Date().toISOString().substr(11, 5) + 'z', - spotter: s.spotter || '' + spotter: s.spotter || '', + source: s.source || '' }))); } else { setData([{ @@ -696,6 +702,7 @@ time: '--:--z', spotter: '' }]); + setActiveSource(''); } } else { setData([{ @@ -705,6 +712,7 @@ time: '--:--z', spotter: '' }]); + setActiveSource(''); } } catch (err) { console.error('DX Cluster error:', err); @@ -715,6 +723,7 @@ time: '--:--z', spotter: '' }]); + setActiveSource(''); } finally { setLoading(false); } @@ -722,9 +731,9 @@ fetchDX(); const interval = setInterval(fetchDX, DEFAULT_CONFIG.refreshIntervals.dxCluster); return () => clearInterval(interval); - }, []); + }, [source]); - return { data, loading }; + return { data, loading, activeSource }; }; // ============================================ @@ -1883,12 +1892,13 @@ ); }; - const DXClusterPanel = ({ spots, loading }) => ( + const DXClusterPanel = ({ spots, loading, activeSource }) => (
🌐 DX CLUSTER
{loading &&
} + {activeSource && {activeSource}} ● LIVE
@@ -2193,7 +2203,10 @@
{/* DX Cluster */}
-
🌐 DX CLUSTER ● LIVE
+
+ 🌐 DX CLUSTER ● LIVE + {dxCluster.activeSource && {dxCluster.activeSource}} +
{dxCluster.data.slice(0, 8).map((s, i) => (
@@ -2316,6 +2329,7 @@ const [useGeolocation, setUseGeolocation] = useState(false); const [theme, setTheme] = useState(config.theme || 'dark'); const [layout, setLayout] = useState(config.layout || 'modern'); + const [dxClusterSource, setDxClusterSource] = useState(config.dxClusterSource || 'auto'); // Calculate grid square from lat/lon useEffect(() => { @@ -2372,7 +2386,8 @@ callsign: callsign.toUpperCase().trim(), location: { lat: latNum, lon: lonNum }, theme: theme, - layout: layout + layout: layout, + dxClusterSource: dxClusterSource }; onSave(newConfig); @@ -2566,6 +2581,34 @@

+ {/* DX Cluster Source Selection */} +
+ + +

+ {dxClusterSource === 'auto' && '→ Automatically selects the best available source'} + {dxClusterSource === 'hamqth' && '→ HamQTH.com DX Cluster feed'} + {dxClusterSource === 'dxheat' && '→ DXHeat.com real-time cluster'} + {dxClusterSource === 'dxsummit' && '→ DXSummit.fi cluster (may be slow)'} + {dxClusterSource === 'dxspider' && '→ G6NHU-2 DX Spider node (dxspider.co.uk)'} +

+
+ {/* Buttons */}