From 3c8558ea1df50da5e9924118e777ae48d76b4bfa Mon Sep 17 00:00:00 2001 From: PaulVua Date: Tue, 10 Feb 2026 10:33:51 +0100 Subject: [PATCH] feat(ui): add signal and network tests to self-test Add two more tests to the modem self-test: - Test 3: Signal Strength (AT+CSQ) with quality thresholds - Test 4: Network Connection (AT+COPS?) with operator name lookup Respects 1 second delay between each AT command. Co-Authored-By: Claude Opus 4.5 --- html/saraR4.html | 137 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/html/saraR4.html b/html/saraR4.html index a1081a1..e802b86 100755 --- a/html/saraR4.html +++ b/html/saraR4.html @@ -392,6 +392,24 @@ Pending + + +
+
+ Signal Strength +
Waiting...
+
+ Pending +
+ + +
+
+ Network Connection +
Waiting...
+
+ Pending +
@@ -1501,6 +1519,14 @@ function resetSelfTestUI() { document.getElementById('test_sim_status').textContent = 'Pending'; document.getElementById('test_sim_detail').textContent = 'Waiting...'; + document.getElementById('test_signal_status').className = 'badge bg-secondary'; + document.getElementById('test_signal_status').textContent = 'Pending'; + document.getElementById('test_signal_detail').textContent = 'Waiting...'; + + document.getElementById('test_network_status').className = 'badge bg-secondary'; + document.getElementById('test_network_status').textContent = 'Pending'; + document.getElementById('test_network_detail').textContent = 'Waiting...'; + // Reset logs document.getElementById('selftest_logs').innerHTML = ''; @@ -1656,6 +1682,117 @@ async function selfTestSequence() { testsFailed++; } + // Delay between AT commands + await delay(1000); + + // Step 4: Test Signal Strength (AT+CSQ) + document.getElementById('selftest_status').innerHTML = ` +
+
+ Testing signal strength... +
`; + + updateTestStatus('signal', 'Testing...', 'Sending AT+CSQ command...', 'bg-info'); + + try { + const signalResponse = await sendATCommand('AT+CSQ', 5); + + const csqMatch = signalResponse.match(/\+CSQ:\s*(\d+),(\d+)/); + if (signalResponse.includes('OK') && csqMatch) { + const signalPower = parseInt(csqMatch[1]); + const qual = parseInt(csqMatch[2]); + + if (signalPower === 99) { + updateTestStatus('signal', 'Failed', 'No signal detected', 'bg-danger'); + testsFailed++; + } else if (signalPower === 0) { + updateTestStatus('signal', 'Warning', 'Very poor signal (0/31)', 'bg-warning'); + testsFailed++; + } else if (signalPower <= 24) { + updateTestStatus('signal', 'Passed', `Poor signal (${signalPower}/31)`, 'bg-success'); + testsPassed++; + } else if (signalPower <= 26) { + updateTestStatus('signal', 'Passed', `Good signal (${signalPower}/31)`, 'bg-success'); + testsPassed++; + } else if (signalPower <= 28) { + updateTestStatus('signal', 'Passed', `Very good signal (${signalPower}/31)`, 'bg-success'); + testsPassed++; + } else { + updateTestStatus('signal', 'Passed', `Excellent signal (${signalPower}/31)`, 'bg-success'); + testsPassed++; + } + } else if (signalResponse.includes('ERROR')) { + updateTestStatus('signal', 'Failed', 'Unable to read signal', 'bg-danger'); + testsFailed++; + } else { + updateTestStatus('signal', 'Warning', 'Unexpected response', 'bg-warning'); + testsFailed++; + } + } catch (error) { + updateTestStatus('signal', 'Failed', error.message, 'bg-danger'); + testsFailed++; + } + + // Delay between AT commands + await delay(1000); + + // Step 5: Test Network Connection (AT+COPS?) + document.getElementById('selftest_status').innerHTML = ` +
+
+ Testing network connection... +
`; + + updateTestStatus('network', 'Testing...', 'Sending AT+COPS? command...', 'bg-info'); + + try { + // Load operators data for network name lookup + let opData = null; + try { + opData = await loadOperatorsData(); + } catch (e) { + addSelfTestLog('Warning: Could not load operators data'); + } + + const networkResponse = await sendATCommand('AT+COPS?', 5); + + const copsMatch = networkResponse.match(/\+COPS:\s*(\d+)(?:,(\d+),"?([^",]+)"?,(\d+))?/); + if (networkResponse.includes('OK') && copsMatch) { + const mode = copsMatch[1]; + const oper = copsMatch[3]; + const act = copsMatch[4]; + + if (oper) { + // Get operator name from lookup table + let operatorName = oper; + if (opData && opData.operators && opData.operators[oper]) { + operatorName = opData.operators[oper].name; + } + + // Get access technology + let actDesc = 'Unknown'; + if (opData && opData.accessTechnology && opData.accessTechnology[act]) { + actDesc = opData.accessTechnology[act]; + } + + updateTestStatus('network', 'Passed', `${operatorName} (${actDesc})`, 'bg-success'); + testsPassed++; + } else { + updateTestStatus('network', 'Warning', 'Not registered to network', 'bg-warning'); + testsFailed++; + } + } else if (networkResponse.includes('ERROR')) { + updateTestStatus('network', 'Failed', 'Unable to get network info', 'bg-danger'); + testsFailed++; + } else { + updateTestStatus('network', 'Warning', 'Unexpected response', 'bg-warning'); + testsFailed++; + } + } catch (error) { + updateTestStatus('network', 'Failed', error.message, 'bg-danger'); + testsFailed++; + } + } catch (error) { addSelfTestLog(`Test sequence error: ${error.message}`); } finally {