diff --git a/html/saraR4.html b/html/saraR4.html index 67e91d2..3e66d21 100755 --- a/html/saraR4.html +++ b/html/saraR4.html @@ -424,17 +424,24 @@
-
- +
+

                     
@@ -1492,9 +1499,27 @@ function update_modem_configMode(param, checked){ // SELF TEST FUNCTIONS // ============================================ +// Global object to store test results for report +let selfTestReport = { + timestamp: '', + deviceId: '', + modemVersion: '', + results: {}, + rawResponses: {} +}; + function runSelfTest() { console.log("Starting Self Test..."); + // Reset report + selfTestReport = { + timestamp: new Date().toISOString(), + deviceId: document.querySelector('.sideBar_sensorName')?.textContent || 'Unknown', + modemVersion: document.getElementById('modem_version')?.textContent || 'Unknown', + results: {}, + rawResponses: {} + }; + // Reset UI resetSelfTestUI(); @@ -1502,9 +1527,10 @@ function runSelfTest() { const modal = new bootstrap.Modal(document.getElementById('selfTestModal')); modal.show(); - // Disable close buttons during test + // Disable buttons during test document.getElementById('selfTestCloseBtn').disabled = true; document.getElementById('selfTestDoneBtn').disabled = true; + document.getElementById('selfTestCopyBtn').disabled = true; document.getElementById('btn_selfTest').disabled = true; // Start test sequence @@ -1547,10 +1573,17 @@ function resetSelfTestUI() { document.getElementById('selftest_summary').innerHTML = ''; } -function addSelfTestLog(message) { +function addSelfTestLog(message, isRaw = false) { const logsEl = document.getElementById('selftest_logs'); const timestamp = new Date().toLocaleTimeString(); - logsEl.innerHTML += `[${timestamp}] ${message}
`; + + if (isRaw) { + // Raw AT response - format nicely + logsEl.textContent += `[${timestamp}] >>> RAW RESPONSE:\n${message}\n<<<\n`; + } else { + logsEl.textContent += `[${timestamp}] ${message}\n`; + } + // Auto-scroll to bottom logsEl.parentElement.scrollTop = logsEl.parentElement.scrollHeight; } @@ -1559,6 +1592,12 @@ function updateTestStatus(testId, status, detail, badge) { document.getElementById(`test_${testId}_status`).className = `badge ${badge}`; document.getElementById(`test_${testId}_status`).textContent = status; document.getElementById(`test_${testId}_detail`).textContent = detail; + + // Store result in report + selfTestReport.results[testId] = { + status: status, + detail: detail + }; } function setConfigMode(enabled) { @@ -1591,18 +1630,24 @@ function setConfigMode(enabled) { function sendATCommand(command, timeout) { return new Promise((resolve, reject) => { - addSelfTestLog(`Sending AT command: ${command}`); + addSelfTestLog(`Sending AT command: ${command} (timeout: ${timeout}s)`); $.ajax({ url: `launcher.php?type=sara&port=ttyAMA2&command=${encodeURIComponent(command)}&timeout=${timeout}`, dataType: 'text', method: 'GET', success: function(response) { - addSelfTestLog(`Response: ${response.replace(/\n/g, ' | ')}`); + // Store raw response in report + selfTestReport.rawResponses[command] = response; + + // Log raw response + addSelfTestLog(response.trim(), true); + resolve(response); }, error: function(xhr, status, error) { addSelfTestLog(`AT command error: ${error}`); + selfTestReport.rawResponses[command] = `ERROR: ${error}`; reject(new Error(error)); } }); @@ -1634,16 +1679,22 @@ async function selfTestSequence() { dataType: 'json', method: 'GET', success: function(data) { - addSelfTestLog(`WiFi status: ${JSON.stringify(data)}`); + addSelfTestLog(`WiFi status received`); + // Store raw response + selfTestReport.rawResponses['WiFi Status'] = JSON.stringify(data, null, 2); resolve(data); }, error: function(xhr, status, error) { addSelfTestLog(`WiFi status error: ${error}`); + selfTestReport.rawResponses['WiFi Status'] = `ERROR: ${error}`; reject(new Error(error)); } }); }); + // Log detailed WiFi info + addSelfTestLog(`Mode: ${wifiResponse.mode}, SSID: ${wifiResponse.ssid}, IP: ${wifiResponse.ip}, Hostname: ${wifiResponse.hostname}`); + if (wifiResponse.connected) { let modeIcon = ''; let modeLabel = ''; @@ -1907,15 +1958,128 @@ async function selfTestSequence() { ${testsPassed} passed ${testsFailed} failed`; - // Enable close buttons + // Store summary in report + selfTestReport.summary = { + passed: testsPassed, + failed: testsFailed, + status: statusText + }; + + // Enable buttons document.getElementById('selfTestCloseBtn').disabled = false; document.getElementById('selfTestDoneBtn').disabled = false; + document.getElementById('selfTestCopyBtn').disabled = false; document.getElementById('btn_selfTest').disabled = false; addSelfTestLog('Self test completed.'); + addSelfTestLog('Click "Copy Report" to share results with support.'); } } +function copySelfTestReport() { + // Build formatted report + let report = `═══════════════════════════════════════════════════════════════ + NEBULEAIR PRO 4G - SELF TEST REPORT +═══════════════════════════════════════════════════════════════ + +📅 Date: ${selfTestReport.timestamp} +🔧 Device ID: ${selfTestReport.deviceId} +📱 Modem Version: ${selfTestReport.modemVersion} + +─────────────────────────────────────────────────────────────── + TEST RESULTS +─────────────────────────────────────────────────────────────── + +`; + + // Add test results + const testNames = { + wifi: '📡 WiFi/Network', + modem: '📟 Modem Connection', + sim: '💳 SIM Card', + signal: '📶 Signal Strength', + network: '🌐 Network Connection' + }; + + for (const [testId, name] of Object.entries(testNames)) { + if (selfTestReport.results[testId]) { + const result = selfTestReport.results[testId]; + const statusIcon = result.status === 'Passed' ? '✅' : + result.status === 'Failed' ? '❌' : + result.status.includes('Hotspot') || result.status.includes('WiFi') || result.status.includes('Ethernet') ? 'ℹ️' : '⚠️'; + report += `${name} + Status: ${statusIcon} ${result.status} + Detail: ${result.detail} + +`; + } + } + + // Add summary + if (selfTestReport.summary) { + report += `─────────────────────────────────────────────────────────────── + SUMMARY +─────────────────────────────────────────────────────────────── + +✅ Passed: ${selfTestReport.summary.passed} +❌ Failed: ${selfTestReport.summary.failed} +📊 Status: ${selfTestReport.summary.status} + +`; + } + + // Add raw AT responses + report += `─────────────────────────────────────────────────────────────── + RAW AT RESPONSES +─────────────────────────────────────────────────────────────── + +`; + + for (const [command, response] of Object.entries(selfTestReport.rawResponses)) { + report += `Command: ${command} +Response: +${response} +─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ + +`; + } + + // Add full logs + report += `─────────────────────────────────────────────────────────────── + DETAILED LOGS +─────────────────────────────────────────────────────────────── + +${document.getElementById('selftest_logs').textContent} + +═══════════════════════════════════════════════════════════════ + END OF REPORT - Generated by NebuleAir Pro 4G +═══════════════════════════════════════════════════════════════ +`; + + // Copy to clipboard + navigator.clipboard.writeText(report).then(function() { + // Show success feedback + const copyBtn = document.getElementById('selfTestCopyBtn'); + const originalHtml = copyBtn.innerHTML; + copyBtn.innerHTML = ` + + + + Copied!`; + copyBtn.classList.remove('btn-outline-primary'); + copyBtn.classList.add('btn-success'); + + setTimeout(function() { + copyBtn.innerHTML = originalHtml; + copyBtn.classList.remove('btn-success'); + copyBtn.classList.add('btn-outline-primary'); + }, 2000); + }).catch(function(err) { + console.error('Failed to copy:', err); + alert('Failed to copy to clipboard. Please select and copy the logs manually.'); + }); +} +