Satellite Health Dashboard

Pathfinder-1 Status: Nominal

Power

Nominal

Thermal

Nominal

Comms

Nominal

Attitude Control

Nominal

Live Telemetry

Alerts Log

    Power System Trends

    Thermal Trends

    Simulation Controls

    Error: A required library is missing.

    '; return; } // --- DATA & STATE --- let satelliteState = { power: { status: 'Nominal', voltage: 28.5, arrayOutput: 155.2 }, thermal: { status: 'Nominal', coreTemp: -5.5 }, comms: { status: 'Nominal', signalStrength: -85.0 }, attitude: { status: 'Nominal', drift: 0.001 } }; let alerts = []; let telemetryHistory = { voltage: [], temp: [] }; // --- CHART INSTANCES & UTILITIES --- let powerChart, thermalChart; const MAX_HISTORY = 30; const format = (val, dec, unit) => `${val.toFixed(dec)}${unit}`; // --- RENDER FUNCTIONS --- const renderAll = () => { try { renderStatus(); renderTelemetry(); renderAlerts(); renderCharts(); } catch(error) { console.error("Dashboard rendering failed:", error); } }; const renderStatus = () => { const statuses = [ satelliteState.power.status, satelliteState.thermal.status, satelliteState.comms.status, satelliteState.attitude.status ]; let overallStatus = 'Nominal'; if (statuses.includes('Critical')) overallStatus = 'Critical'; else if (statuses.includes('Warning')) overallStatus = 'Warning'; const setStatus = (elId, status) => { const el = document.getElementById(elId); el.textContent = status; el.className = `shd-status-indicator status-${status.toLowerCase()}`; }; setStatus('shd-overall-status', overallStatus); setStatus('shd-power-status', satelliteState.power.status); setStatus('shd-thermal-status', satelliteState.thermal.status); setStatus('shd-comms-status', satelliteState.comms.status); setStatus('shd-attitude-status', satelliteState.attitude.status); }; const renderTelemetry = () => { const container = document.getElementById('shd-telemetry-readouts'); container.innerHTML = `
    Battery Voltage${format(satelliteState.power.voltage, 2, 'V')}
    Solar Array Output${format(satelliteState.power.arrayOutput, 1, 'W')}
    Core Temperature${format(satelliteState.thermal.coreTemp, 1, '°C')}
    Signal Strength${format(satelliteState.comms.signalStrength, 1, 'dBm')}
    Attitude Drift${format(satelliteState.attitude.drift, 4, '°/s')}
    `; }; const renderAlerts = () => { const log = document.getElementById('shd-alerts-log'); log.innerHTML = alerts.map(a => `
  • ${a.time}${a.message}
  • `).join(''); }; const renderCharts = () => { const commonOptions = { chart: { height: 300, animations: { easing: 'linear', dynamicAnimation: { speed: 1000 } } }, stroke: { curve: 'smooth', width: 2 }, markers: { size: 0 }, xaxis: { type: 'datetime', range: 30 * 1000 } }; if (!powerChart) { const powerOptions = { ...commonOptions, series: [{ name: 'Voltage', data: telemetryHistory.voltage }], title: { text: 'Battery Voltage (V)' }, colors: ['var(--shd-accent-color)'] }; powerChart = new ApexCharts(document.querySelector("#shd-power-chart"), powerOptions); powerChart.render(); } else { powerChart.updateSeries([{ data: telemetryHistory.voltage }]); } if (!thermalChart) { const thermalOptions = { ...commonOptions, series: [{ name: 'Temperature', data: telemetryHistory.temp }], title: { text: 'Core Temperature (°C)' }, colors: ['var(--shd-warning-color)'] }; thermalChart = new ApexCharts(document.querySelector("#shd-thermal-chart"), thermalOptions); thermalChart.render(); } else { thermalChart.updateSeries([{ data: telemetryHistory.temp }]); } }; // --- SIMULATION & EVENT HANDLING --- const addAlert = (type, message) => { const time = new Date().toLocaleTimeString('en-US', { hour12: false }); alerts.unshift({ time, type, message }); if (alerts.length > 20) alerts.pop(); }; const runSimulation = () => { // Power sim satelliteState.power.voltage += (Math.random() - 0.5) * 0.1; if (satelliteState.power.voltage > 29) satelliteState.power.voltage = 29; satelliteState.power.status = satelliteState.power.voltage < 26.5 ? 'Warning' : 'Nominal'; // Thermal sim satelliteState.thermal.coreTemp += (Math.random() - 0.5) * 0.5; if (satelliteState.thermal.coreTemp > 50 || satelliteState.thermal.coreTemp < -20) satelliteState.thermal.status = 'Critical'; else if (satelliteState.thermal.coreTemp > 40 || satelliteState.thermal.coreTemp < -15) satelliteState.thermal.status = 'Warning'; else satelliteState.thermal.status = 'Nominal'; // Comms sim if(satelliteState.comms.status !== 'Critical') { satelliteState.comms.signalStrength += (Math.random() - 0.45); if(satelliteState.comms.signalStrength > -80) satelliteState.comms.signalStrength = -80; if(satelliteState.comms.signalStrength < -110) satelliteState.comms.status = 'Critical'; } // Update history const now = new Date().getTime(); telemetryHistory.voltage.push([now, satelliteState.power.voltage]); telemetryHistory.temp.push([now, satelliteState.thermal.coreTemp]); if (telemetryHistory.voltage.length > MAX_HISTORY) { telemetryHistory.voltage.shift(); telemetryHistory.temp.shift(); } renderAll(); }; // Tab Navigation const tabButtons = document.querySelectorAll('.shd-tab-button'); const tabContents = document.querySelectorAll('.shd-tab-content'); const nextBtn = document.getElementById('shd-next-btn'); const prevBtn = document.getElementById('shd-prev-btn'); const switchTab = (tabId) => { tabContents.forEach(c => c.style.display = 'none'); tabButtons.forEach(b => b.classList.remove('active')); const activeContent = document.getElementById(tabId); const activeButton = document.querySelector(`.shd-tab-button[data-tab="${tabId}"]`); if (activeContent && activeButton) { activeContent.style.display = 'block'; activeButton.classList.add('active'); } updateNavButtons(); }; const updateNavButtons = () => { const i = [...tabButtons].findIndex(b => b.classList.contains('active')); prevBtn.disabled = i === 0; nextBtn.disabled = i === tabButtons.length - 1; }; tabButtons.forEach(b => b.addEventListener('click', () => switchTab(b.dataset.tab))); nextBtn.addEventListener('click', () => { const i = [...tabButtons].findIndex(b=>b.classList.contains('active')); if (i < tabButtons.length - 1) switchTab(tabButtons[i+1].dataset.tab); }); prevBtn.addEventListener('click', () => { const i = [...tabButtons].findIndex(b=>b.classList.contains('active')); if (i > 0) switchTab(tabButtons[i-1].dataset.tab); }); // Simulation controls document.querySelector('.shd-grid').addEventListener('click', e => { if(e.target.tagName !== 'BUTTON') return; const event = e.target.dataset.event; if(event === 'power-warn') { satelliteState.power.voltage = 26.2; addAlert('warning', 'Battery voltage dropping below threshold.'); } else if (event === 'temp-crit') { satelliteState.thermal.coreTemp = 55.0; addAlert('critical', 'Core temperature exceeds critical limits!'); } else if (event === 'comms-loss') { satelliteState.comms.status = 'Critical'; satelliteState.comms.signalStrength = -120; addAlert('critical', 'AOS - Acquisition of Signal: FAILED'); } else if (event === 'normalize') { satelliteState = { power: { status: 'Nominal', voltage: 28.5, arrayOutput: 155.2 }, thermal: { status: 'Nominal', coreTemp: -5.5 }, comms: { status: 'Nominal', signalStrength: -85.0 }, attitude: { status: 'Nominal', drift: 0.001 } }; addAlert('nominal', 'All systems returned to nominal state.'); } }); // PDF Export document.getElementById('shd-download-pdf-btn').addEventListener('click', function() { const btn = this; btn.textContent = 'Generating...'; btn.disabled = true; const content = document.getElementById('shd-pdf-capture-area'); html2canvas(content, { scale: 2, backgroundColor: getComputedStyle(document.documentElement).getPropertyValue('--shd-bg-color') }).then(canvas => { const doc = new jsPDF(); const imgData = canvas.toDataURL('image/png'); doc.setFontSize(18); doc.text('Satellite Status Report: Pathfinder-1', 14, 22); doc.setFontSize(11); doc.setTextColor(100); doc.text(`Generated on: ${new Date().toUTCString()}`, 14, 29); const imgWidth = doc.internal.pageSize.getWidth() - 28; const imgHeight = (canvas.height * imgWidth) / canvas.width; doc.addImage(imgData, 'PNG', 14, 40, imgWidth, imgHeight); doc.save('Satellite_Status_Report.pdf'); }).finally(() => { btn.textContent = 'Download Status Report'; btn.disabled = false; }); }); // --- INITIALIZATION --- setInterval(runSimulation, 2000); setInterval(() => { document.getElementById('shd-utc-time').textContent = new Date().toUTCString().slice(17, 25) + ' UTC'; }, 1000); renderAll(); });
    Scroll to Top