diff --git a/html/saraR4.html b/html/saraR4.html
index d1f2107..dbfba94 100755
--- a/html/saraR4.html
+++ b/html/saraR4.html
@@ -1774,256 +1774,6 @@ async function selfTestSequence() {
await delay(300);
- // Step 0: Check WiFi / Network status (informational, no pass/fail)
- document.getElementById('selftest_status').innerHTML = `
-
-
-
Checking network status...
-
`;
-
- updateTestStatus('wifi', 'Checking...', 'Getting network info...', 'bg-info');
-
- try {
- const wifiResponse = await new Promise((resolve, reject) => {
- $.ajax({
- url: 'launcher.php?type=wifi_status',
- dataType: 'json',
- method: 'GET',
- success: function(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 = '';
- let badgeClass = 'bg-info';
-
- if (wifiResponse.mode === 'hotspot') {
- modeIcon = '📡';
- modeLabel = 'Hotspot';
- badgeClass = 'bg-warning text-dark';
- } else if (wifiResponse.mode === 'wifi') {
- modeIcon = '📶';
- modeLabel = 'WiFi';
- badgeClass = 'bg-info';
- } else if (wifiResponse.mode === 'ethernet') {
- modeIcon = '🔌';
- modeLabel = 'Ethernet';
- badgeClass = 'bg-info';
- }
-
- const detailText = `${wifiResponse.ssid} | ${wifiResponse.ip} | ${wifiResponse.hostname}.local`;
- updateTestStatus('wifi', modeLabel, detailText, badgeClass);
- } else {
- updateTestStatus('wifi', 'Disconnected', 'No network connection', 'bg-secondary');
- }
- } catch (error) {
- updateTestStatus('wifi', 'Error', error.message, 'bg-secondary');
- }
-
- await delay(500);
-
- // Step 1: Enable config mode
- document.getElementById('selftest_status').innerHTML = `
-
-
-
Enabling configuration mode...
-
`;
-
- await setConfigMode(true);
-
- // Wait for SARA script to release the port (2 seconds should be enough)
- addSelfTestLog('Waiting for modem port to be available...');
- await delay(2000);
-
- // Step 2: Test Modem Connection (ATI)
- document.getElementById('selftest_status').innerHTML = `
-
-
-
Testing modem connection...
-
`;
-
- updateTestStatus('modem', 'Testing...', 'Sending ATI command...', 'bg-info');
-
- try {
- const modemResponse = await sendATCommand('ATI', 5);
-
- if (modemResponse.includes('OK') && (modemResponse.toUpperCase().includes('SARA-R5') || modemResponse.toUpperCase().includes('SARA-R4'))) {
- // Extract model
- const modelMatch = modemResponse.match(/SARA-R[45]\d*[A-Z]*-\d+[A-Z]*-\d+/i);
- const model = modelMatch ? modelMatch[0] : 'SARA module';
- updateTestStatus('modem', 'Passed', `Model: ${model}`, 'bg-success');
- testsPassed++;
- } else if (modemResponse.includes('OK')) {
- updateTestStatus('modem', 'Passed', 'Modem responding', 'bg-success');
- testsPassed++;
- } else {
- updateTestStatus('modem', 'Failed', 'No valid response', 'bg-danger');
- testsFailed++;
- }
- } catch (error) {
- updateTestStatus('modem', 'Failed', error.message, 'bg-danger');
- testsFailed++;
- }
-
- // Delay between AT commands
- await delay(1000);
-
- // Step 3: Test SIM Card (AT+CCID?)
- document.getElementById('selftest_status').innerHTML = `
-
-
-
Testing SIM card...
-
`;
-
- updateTestStatus('sim', 'Testing...', 'Sending AT+CCID? command...', 'bg-info');
-
- try {
- const simResponse = await sendATCommand('AT+CCID?', 5);
-
- const ccidMatch = simResponse.match(/\+CCID:\s*(\d{18,22})/);
- if (simResponse.includes('OK') && ccidMatch) {
- const iccid = ccidMatch[1];
- // Show last 4 digits only for privacy
- const maskedIccid = '****' + iccid.slice(-4);
- updateTestStatus('sim', 'Passed', `ICCID: ...${maskedIccid}`, 'bg-success');
- testsPassed++;
- } else if (simResponse.includes('ERROR')) {
- updateTestStatus('sim', 'Failed', 'SIM card not detected', 'bg-danger');
- testsFailed++;
- } else {
- updateTestStatus('sim', 'Warning', 'Unable to read ICCID', 'bg-warning');
- testsFailed++;
- }
- } catch (error) {
- updateTestStatus('sim', 'Failed', error.message, 'bg-danger');
- 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++;
- }
-
// ═══════════════════════════════════════════════════════
// SENSOR TESTS - Test enabled sensors based on config
// ═══════════════════════════════════════════════════════
@@ -2049,22 +1799,19 @@ async function selfTestSequence() {
}
// Create sensor test UI entries dynamically
- if (sensorTests.length > 0) {
- document.getElementById('sensor_tests_separator').style.display = '';
- const sensorContainer = document.getElementById('sensor_tests_container');
- sensorContainer.innerHTML = '';
+ const sensorContainer = document.getElementById('sensor_tests_container');
+ sensorContainer.innerHTML = '';
- sensorTests.forEach(sensor => {
- sensorContainer.innerHTML += `
-
-
-
${sensor.name}
-
Waiting...
-
-
Pending
-
`;
- });
- }
+ sensorTests.forEach(sensor => {
+ sensorContainer.innerHTML += `
+
+
+
${sensor.name}
+
Waiting...
+
+
Pending
+
`;
+ });
addSelfTestLog('');
addSelfTestLog('────────────────────────────────────────────────────────');
@@ -2204,6 +1951,266 @@ async function selfTestSequence() {
}
}
+ // ═══════════════════════════════════════════════════════
+ // COMMUNICATION TESTS - WiFi, Modem, SIM, Signal, Network
+ // ═══════════════════════════════════════════════════════
+ addSelfTestLog('');
+ addSelfTestLog('────────────────────────────────────────────────────────');
+ addSelfTestLog('COMMUNICATION TESTS');
+ addSelfTestLog('────────────────────────────────────────────────────────');
+
+ document.getElementById('comm_tests_separator').style.display = '';
+
+ // Check WiFi / Network status (informational, no pass/fail)
+ document.getElementById('selftest_status').innerHTML = `
+
+
+
Checking network status...
+
`;
+
+ updateTestStatus('wifi', 'Checking...', 'Getting network info...', 'bg-info');
+
+ try {
+ const wifiResponse = await new Promise((resolve, reject) => {
+ $.ajax({
+ url: 'launcher.php?type=wifi_status',
+ dataType: 'json',
+ method: 'GET',
+ success: function(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 = '';
+ let badgeClass = 'bg-info';
+
+ if (wifiResponse.mode === 'hotspot') {
+ modeIcon = '📡';
+ modeLabel = 'Hotspot';
+ badgeClass = 'bg-warning text-dark';
+ } else if (wifiResponse.mode === 'wifi') {
+ modeIcon = '📶';
+ modeLabel = 'WiFi';
+ badgeClass = 'bg-info';
+ } else if (wifiResponse.mode === 'ethernet') {
+ modeIcon = '🔌';
+ modeLabel = 'Ethernet';
+ badgeClass = 'bg-info';
+ }
+
+ const detailText = `${wifiResponse.ssid} | ${wifiResponse.ip} | ${wifiResponse.hostname}.local`;
+ updateTestStatus('wifi', modeLabel, detailText, badgeClass);
+ } else {
+ updateTestStatus('wifi', 'Disconnected', 'No network connection', 'bg-secondary');
+ }
+ } catch (error) {
+ updateTestStatus('wifi', 'Error', error.message, 'bg-secondary');
+ }
+
+ await delay(500);
+
+ // Enable config mode
+ document.getElementById('selftest_status').innerHTML = `
+
+
+
Enabling configuration mode...
+
`;
+
+ await setConfigMode(true);
+
+ // Wait for SARA script to release the port (2 seconds should be enough)
+ addSelfTestLog('Waiting for modem port to be available...');
+ await delay(2000);
+
+ // Test Modem Connection (ATI)
+ document.getElementById('selftest_status').innerHTML = `
+
+
+
Testing modem connection...
+
`;
+
+ updateTestStatus('modem', 'Testing...', 'Sending ATI command...', 'bg-info');
+
+ try {
+ const modemResponse = await sendATCommand('ATI', 5);
+
+ if (modemResponse.includes('OK') && (modemResponse.toUpperCase().includes('SARA-R5') || modemResponse.toUpperCase().includes('SARA-R4'))) {
+ // Extract model
+ const modelMatch = modemResponse.match(/SARA-R[45]\d*[A-Z]*-\d+[A-Z]*-\d+/i);
+ const model = modelMatch ? modelMatch[0] : 'SARA module';
+ updateTestStatus('modem', 'Passed', `Model: ${model}`, 'bg-success');
+ testsPassed++;
+ } else if (modemResponse.includes('OK')) {
+ updateTestStatus('modem', 'Passed', 'Modem responding', 'bg-success');
+ testsPassed++;
+ } else {
+ updateTestStatus('modem', 'Failed', 'No valid response', 'bg-danger');
+ testsFailed++;
+ }
+ } catch (error) {
+ updateTestStatus('modem', 'Failed', error.message, 'bg-danger');
+ testsFailed++;
+ }
+
+ // Delay between AT commands
+ await delay(1000);
+
+ // Test SIM Card (AT+CCID?)
+ document.getElementById('selftest_status').innerHTML = `
+
+
+
Testing SIM card...
+
`;
+
+ updateTestStatus('sim', 'Testing...', 'Sending AT+CCID? command...', 'bg-info');
+
+ try {
+ const simResponse = await sendATCommand('AT+CCID?', 5);
+
+ const ccidMatch = simResponse.match(/\+CCID:\s*(\d{18,22})/);
+ if (simResponse.includes('OK') && ccidMatch) {
+ const iccid = ccidMatch[1];
+ // Show last 4 digits only for privacy
+ const maskedIccid = '****' + iccid.slice(-4);
+ updateTestStatus('sim', 'Passed', `ICCID: ...${maskedIccid}`, 'bg-success');
+ testsPassed++;
+ } else if (simResponse.includes('ERROR')) {
+ updateTestStatus('sim', 'Failed', 'SIM card not detected', 'bg-danger');
+ testsFailed++;
+ } else {
+ updateTestStatus('sim', 'Warning', 'Unable to read ICCID', 'bg-warning');
+ testsFailed++;
+ }
+ } catch (error) {
+ updateTestStatus('sim', 'Failed', error.message, 'bg-danger');
+ testsFailed++;
+ }
+
+ // Delay between AT commands
+ await delay(1000);
+
+ // 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);
+
+ // 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 {
@@ -2288,17 +2295,17 @@ GPS Location: ${selfTestReport.latitude || 'N/A'}, ${selfTestReport.longitude
`;
- // Add test results
+ // Add test results (sensors first, then communication)
const testNames = {
+ npm: 'NextPM (Particles)',
+ bme280: 'BME280 (Temp/Hum)',
+ noise: 'Noise Sensor',
+ envea: 'Envea (Gas Sensors)',
wifi: 'WiFi/Network',
modem: 'Modem Connection',
sim: 'SIM Card',
signal: 'Signal Strength',
- network: 'Network Connection',
- npm: 'NextPM (Particles)',
- bme280: 'BME280 (Temp/Hum)',
- noise: 'Noise Sensor',
- envea: 'Envea (Gas Sensors)'
+ network: 'Network Connection'
};
for (const [testId, name] of Object.entries(testNames)) {