document.addEventListener('DOMContentLoaded', function() { // Helper to format hashrate function formatHashrate(mhs) { if (mhs >= 1000) { return (mhs / 1000).toFixed(2) + ' GH/s'; } return parseFloat(mhs).toFixed(2) + ' MH/s'; } // Initialize Chart const ctx = document.getElementById('hashrateChart').getContext('2d'); const hashrateChart = new Chart(ctx, { type: 'line', data: { labels: [], datasets: [{ label: 'Hashrate', data: [], borderColor: '#0d6efd', backgroundColor: 'rgba(13, 110, 253, 0.1)', borderWidth: 2, fill: true, tension: 0.4 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { callbacks: { label: function(context) { return formatHashrate(context.raw); } } } }, scales: { x: { grid: { color: '#333' }, ticks: { color: '#aaa' } }, y: { grid: { color: '#333' }, ticks: { color: '#aaa' }, beginAtZero: true } } } }); // Helper to format large numbers function formatNumber(num) { return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,'); } function updateDashboard() { fetch('/api/data') .then(response => response.json()) .then(data => { console.log("API Data:", data); // Debugging const summary = data.summary; const devs = data.devs; const pools = data.pools; // Update Top Stats if (summary) { const mhs = summary['MHS 5s'] || summary['MHS av'] || 0; // Parse unit const formatted = formatHashrate(mhs); // Check if GH/s or MH/s let unit = 'MH/s'; let val = mhs; if (formatted.includes('GH/s')) { unit = 'GH/s'; val = (mhs / 1000).toFixed(2); } else { val = parseFloat(mhs).toFixed(2); } const statMhs = document.getElementById('stat-mhs'); if (statMhs) { statMhs.innerText = val; const unitElem = document.querySelector('#stat-mhs').nextElementSibling; if(unitElem) unitElem.innerText = unit; } document.getElementById('stat-accepted').innerText = formatNumber(summary['Accepted'] || 0); document.getElementById('stat-hw').innerText = formatNumber(summary['Hardware Errors'] || 0); // Update Chart const now = new Date(); const timeLabel = now.getHours() + ':' + String(now.getMinutes()).padStart(2, '0') + ':' + String(now.getSeconds()).padStart(2, '0'); if (hashrateChart.data.labels.length > 60) { hashrateChart.data.labels.shift(); hashrateChart.data.datasets[0].data.shift(); } hashrateChart.data.labels.push(timeLabel); hashrateChart.data.datasets[0].data.push(mhs); hashrateChart.update(); } // Update Device Count if (devs) { document.getElementById('stat-devices').innerText = devs.length; } // Update Devs Table & Max Temp let maxTemp = 0; const tbody = document.getElementById('devs-table-body'); if (devs && devs.length > 0) { tbody.innerHTML = ''; // Clear only if we have data devs.forEach(dev => { let temp = dev['Temperature'] || 0; if (temp > maxTemp) maxTemp = temp; const tr = document.createElement('tr'); tr.innerHTML = `