Files
nebuleair_pro_4g/html/saraR4.html
PaulVua fe604791f0 Enable i18n language switching on all pages and hide incomplete features
Added i18n.js script to all main pages (index, database, saraR4, wifi, logs, admin) to enable language switching functionality across the entire application. Commented out Map and Terminal menu items in the sidebar as these pages are not yet ready for production use.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-06 16:38:28 +01:00

948 lines
41 KiB
HTML
Executable File

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NebuleAir</title>
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
<style>
body {
overflow-x: hidden;
}
#sidebar a.nav-link {
position: relative;
display: flex;
align-items: center;
}
#sidebar a.nav-link:hover {
background-color: rgba(0, 0, 0, 0.5);
}
#sidebar a.nav-link svg {
margin-right: 8px; /* Add spacing between icons and text */
}
#sidebar {
transition: transform 0.3s ease-in-out;
}
.offcanvas-backdrop {
z-index: 1040;
}
</style>
</head>
<body>
<!-- Topbar -->
<span id="topbar"></span>
<!-- Sidebar Offcanvas for Mobile -->
<div class="offcanvas offcanvas-start text-white bg-dark" tabindex="-1" id="sidebarOffcanvas" aria-labelledby="sidebarOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="sidebarOffcanvasLabel">NebuleAir</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body" id="sidebar_mobile">
</div>
</div>
<div class="container-fluid mt-5">
<div class="row">
<aside class="col-md-2 col-lg-1 d-none d-md-block vh-100 position-fixed bg-dark text-white" id="sidebar">
</aside>
<!-- Main content -->
<main class="col-md-10 ms-sm-auto col-lg-11 offset-md-2 offset-lg-1 px-md-4">
<h1 class="mt-4">Modem 4G</h1>
<h4 id="modem_version"></h4>
<p>Votre capteur est équipé d'un modem 4G et d'une carte SIM afin d'envoyer les mesures sur internet.</p>
<div class="form-check form-switch mb-2">
<input class="form-check-input" type="checkbox" role="switch" id="check_modem_configMode" onchange="update_modem_configMode('modem_config_mode',this.checked)">
<label class="form-check-label" for="check_modem_configMode">Mode configuration</label>
</div>
<span id="modem_status_message"></span>
<!--
<h3>
Status
<span id="modem-status" class="badge">Loading...</span>
</h3>
-->
<div class="row mb-3">
<div class="col-sm-2">
<div class="card">
<div class="card-body">
<p class="card-text">General information. </p>
<button class="btn btn-primary" onclick="getData_saraR4('ttyAMA2', 'ATI', 1)">Get Data</button>
<div id="loading_ttyAMA2_ATI" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
<div id="response_ttyAMA2_ATI"></div>
</div>
</div>
</div>
<div class="col-sm-2">
<div class="card">
<div class="card-body">
<p class="card-text">SIM card information.</p>
<button class="btn btn-primary" onclick="getData_saraR4('ttyAMA2', 'AT+CCID?', 1)">Get Data</button>
<div id="loading_ttyAMA2_AT_CCID_" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
<div id="response_ttyAMA2_AT_CCID_"></div>
</div>
</div>
</div>
<div class="col-sm-2">
<div class="card">
<div class="card-body">
<p class="card-text">Actual Network connection</p>
<button class="btn btn-primary" onclick="getData_saraR4('ttyAMA2', 'AT+COPS?', 2)">Get Data</button>
<div id="loading_ttyAMA2_AT_COPS_" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
<div id="response_ttyAMA2_AT_COPS_"></div>
</table>
</div>
</div>
</div>
<div class="col-sm-2">
<div class="card">
<div class="card-body">
<p class="card-text">Signal strength </p>
<button class="btn btn-primary" onclick="getData_saraR4('ttyAMA2', 'AT+CSQ', 1)">Get Data</button>
<div id="loading_ttyAMA2_AT_CSQ" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
<div id="response_ttyAMA2_AT_CSQ"></div>
</table>
</div>
</div>
</div>
<div class="col-sm-2">
<div class="card">
<div class="card-body">
<p class="card-text">Modem Reset </p>
<button class="btn btn-danger" onclick="getData_saraR4('ttyAMA2', 'AT+CFUN=15', 1)">Reset</button>
<div id="loading_ttyAMA2_AT_CFUN_15" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
<div id="response_ttyAMA2_AT_CFUN_15"></div>
</table>
</div>
</div>
</div>
</div>
<h3>Connexion 4G Network</h3>
<div class="row mb-3">
<div class="col-sm-6">
<div class="card text-dark bg-light">
<div class="card-body">
<p class="card-text">Network scan. Attention: 2 min scan.</p>
<p class="card-text">Orange FR (20801), SFR (20810), Bouygues (20820)</p>
<button class="btn btn-primary" onclick="getData_saraR4('ttyAMA2', 'AT+COPS=?', 120)">Scan</button>
<div id="loading_ttyAMA2_AT_COPS__" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
<div id="response_ttyAMA2_AT_COPS__"></div>
<div id="table-network"></div>
</div>
</div>
</div>
<div class="col-sm-3">
<div class="card text-dark bg-light">
<div class="card-body">
<p class="card-text">Network connexion.</p>
<div class="input-group input-group-sm mb-3">
<span class="input-group-text" id="inputGroup-sizing-sm">Numeric Operator</span>
<input type="text" id="messageInput_network" class="form-control" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-sm">
</div>
<button class="btn btn-primary" onclick="connectNetwork_saraR4('ttyAMA2', document.getElementById('messageInput_network').value, 60)">Connect</button>
<div id="loading_ttyAMA2_AT_COPS_Connect" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
<div id="response_ttyAMA2_AT_COPS_Connect"></div>
</div>
</div>
</div>
<div class="col-sm-3">
<div class="card text-dark bg-light">
<div class="card-body">
<p class="card-text">APN</p>
<div class="input-group input-group-sm mb-3">
<span class="input-group-text" id="inputGroup-sizing-sm">Address</span>
<input type="text" id="messageInput_APN" class="form-control" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-sm">
</div>
<button class="btn btn-primary" onclick="connectAPN_saraR4('ttyAMA2', document.getElementById('messageInput_APN').value, 5)">Set APN</button>
<button class="btn btn-secondary" onclick="getData_saraR4('ttyAMA2','AT+CGDCONT?', 5)">Get APN</button>
<div id="loading_ttyAMA2_APN" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
<div id="response_ttyAMA2_APN"></div>
<div id="loading_ttyAMA2_AT_CGDCONT_" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
<div id="response_ttyAMA2_AT_CGDCONT_"></div>
</div>
</div>
</div>
</div>
<!--
<h3>MQTT</h3>
<div class="row mb-3">
<div class="col-sm-4">
<div class="card">
<div class="card-body">
<p class="card-text">Get config.</p>
<button class="btn btn-primary" onclick="mqtt_getConfig_saraR4('ttyAMA2', 2)">Get Data</button>
<div id="loading_mqtt_getConfig" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
<div id="response_mqtt_getConfig"></div>
</div>
</div>
</div>
<div class="col-sm-4">
<div class="card">
<div class="card-body">
<p class="card-text">Login / logout</p>
<button class="btn btn-success" onclick="mqtt_login_logout('ttyAMA2', 1, 6)">Login </button>
<button class="btn btn-danger" onclick="mqtt_login_logout('ttyAMA2', 0, 6)">Logout </button>
<div id="loading_mqtt_login_logout" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
<div id="response_mqtt_login_logout"></div>
</div>
</div>
</div>
<div class="col-sm-4">
<div class="card">
<div class="card-body">
<p class="card-text">Send message (MQTT publish) .</p>
<div class="input-group input-group-sm mb-3">
<span class="input-group-text" id="inputGroup-sizing-sm">Text</span>
<input type="text" id="MQTTmessageInput" class="form-control" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-sm">
</div>
<button class="btn btn-primary" onclick="mqtt_publish('ttyAMA2', document.getElementById('MQTTmessageInput').value, 2)">Send Message</button>
<div id="loading_mqtt_publish" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
<div id="response_mqtt_publish"></div>
</div>
</div>
</div>
</div>
-->
<h3>Test HTTP server comm.</h3>
<div class="row mb-3">
<!-- SET URL -->
<div class="col-sm-4">
<div class="card">
<div class="card-body">
<p class="card-text">Test communication with the server.</p>
<button class="btn btn-primary" onclick="ping_test()">Test</button>
<div id="loading_ping" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
<div id="response_ping"></div>
</div>
</div>
</div>
<div class="col-sm-4">
<div class="card">
<div class="card-body">
<p class="card-text">Setup PSD connection.</p>
<button class="btn btn-primary" onclick="PSD_setup()">Start</button>
<div id="loading_PSD" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
<div id="response_psd_setup"></div>
</div>
</div>
</div>
<div class="col-sm-3">
<div class="card">
<div class="card-body">
<p class="card-text">Setup Server Hostname.</p>
<div class="input-group input-group-sm mb-3">
<span class="input-group-text" id="inputGroup-sizing-sm">Server name</span>
<input type="text" id="messageInput_server" class="form-control" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-sm">
</div>
<button class="btn btn-primary" onclick="setupServerHostname('ttyAMA2', document.getElementById('messageInput_server').value, 0)">Set</button>
<div id="loading_serverHostname" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
<div id="response_serverHostname"></div>
</div>
</div>
</div>
</div>
<h3>Send message (test)</h3>
<div class="row mb-3">
<!-- SET URL -->
<div class="col-sm-4">
<div class="card">
<div class="card-body">
<p class="card-text">Set url (HTTP).</p>
<button class="btn btn-primary" onclick="setURL_saraR4('ttyAMA2', 'data.nebuleair.fr')">Set URL</button>
<div id="loading_ttyAMA2_setURL" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
<div id="response_ttyAMA2_setURL"></div>
</div>
</div>
</div>
<!-- WRITE MESSAGE to memory -->
<div class="col-sm-4">
<div class="card">
<div class="card-body">
<p class="card-text">Write message (local storage).</p>
<div class="input-group input-group-sm mb-3">
<span class="input-group-text" id="inputGroup-sizing-sm">Text</span>
<input type="text" id="messageInput" class="form-control" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-sm">
</div>
<button class="btn btn-primary" onclick="writeMessage_saraR4('ttyAMA2', document.getElementById('messageInput').value , 'write')">Write </button>
<button class="btn btn-warning" onclick="writeMessage_saraR4('ttyAMA2', 'Hello', 'read')">Read </button>
<button class="btn btn-danger" onclick="writeMessage_saraR4('ttyAMA2', 'Hello', 'erase')">Empty </button>
<div id="loading_ttyAMA2_message_write" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
<div id="response_ttyAMA2_message_write"></div>
</div>
</div>
</div>
<!-- Send MESSAGE -->
<div class="col-sm-4">
<div class="card">
<div class="card-body">
<p class="card-text">Send message .</p>
<button class="btn btn-primary" onclick="sendMessage_saraR4('ttyAMA2', '/pro_4G/notif_message.php')">Send Message</button>
<div id="loading_ttyAMA2_message_send" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
<div id="response_ttyAMA2_message_send"></div>
</div>
</div>
</div>
</div>
<!-- toast -->
<div class="toast-container position-fixed bottom-0 end-0 p-3">
<div id="liveToast" class="toast align-items-center text-bg-primary border-1" role="alert" aria-live="assertive" aria-atomic="true">
<div class="d-flex">
<div class="toast-body">
Hello, world! This is a toast message.
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
</div>
</div>
</main>
</div>
</div>
<!-- JAVASCRIPT -->
<!-- Link Ajax locally -->
<script src="assets/jquery/jquery-3.7.1.min.js"></script>
<!-- Link Bootstrap JS and Popper.js locally -->
<script src="assets/js/bootstrap.bundle.js"></script>
<!-- i18n translation system -->
<script src="assets/js/i18n.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
const elementsToLoad = [
{ id: 'topbar', file: 'topbar.html' },
{ id: 'sidebar', file: 'sidebar.html' },
{ id: 'sidebar_mobile', file: 'sidebar.html' }
];
elementsToLoad.forEach(({ id, file }) => {
fetch(file)
.then(response => response.text())
.then(data => {
const element = document.getElementById(id);
if (element) {
element.innerHTML = data;
}
})
.catch(error => console.error(`Error loading ${file}:`, error));
});
//OLD way to retreive data from JSON
/*
fetch('../config.json') // Replace 'deviceID.txt' with 'config.json'
.then(response => response.json()) // Parse response as JSON
.then(data => {
console.log("Getting config file (onload)");
//modem config mode
const check_modem_configMode = document.getElementById("check_modem_configMode");
check_modem_configMode.checked = data.modem_config_mode;
console.log("Modem configuration: " + data.modem_config_mode);
})
*/
//NEW way to get data from SQLITE
$.ajax({
url: 'launcher.php?type=get_config_sqlite',
dataType:'json',
//dataType: 'json', // Specify that you expect a JSON response
method: 'GET', // Use GET or POST depending on your needs
success: function(response) {
console.log("Getting SQLite config table:");
console.log(response);
//modem_version
const modem_version_html = document.getElementById("modem_version");
modem_version_html.innerText = response.modem_version;
// Set checkbox state based on the response data
const check_modem_configMode = document.getElementById("check_modem_configMode");
if (check_modem_configMode) {
check_modem_configMode.checked = response.modem_config_mode;
console.log("Modem configuration: " + response.modem_config_mode);
} else {
console.error("Checkbox element not found");
}
},
error: function(xhr, status, error) {
console.error('AJAX request failed:', status, error);
}
});
});
window.onload = function() {
getModem_busy_status();
setInterval(getModem_busy_status, 1000);
//NEW way to get config (SQLite)
$.ajax({
url: 'launcher.php?type=get_config_sqlite',
dataType:'json',
//dataType: 'json', // Specify that you expect a JSON response
method: 'GET', // Use GET or POST depending on your needs
success: function(response) {
console.log("Getting SQLite config table:");
console.log(response);
//device name_side bar
const elements = document.querySelectorAll('.sideBar_sensorName');
elements.forEach((element) => {
element.innerText = response.deviceName;
});
//device name html page title
if (response.deviceName) {
document.title = response.deviceName;
}
},
error: function(xhr, status, error) {
console.error('AJAX request failed:', status, error);
}
});//end AJAX
//get local RTC
$.ajax({
url: 'launcher.php?type=RTC_time',
dataType: 'text', // Specify that you expect a JSON response
method: 'GET', // Use GET or POST depending on your needs
success: function(response) {
console.log("Local RTC: " + response);
const RTC_Element = document.getElementById("RTC_time");
RTC_Element.textContent = response;
},
error: function(xhr, status, error) {
console.error('AJAX request failed:', status, error);
}
});
}
function getData_saraR4(port, command, timeout){
console.log("Data from SaraR4");
console.log("Port: " + port );
console.log("Command: " + command );
console.log("Timeout: " + timeout );
const safeCommand = command.replace(/[?+=]/g, "_");
console.log(safeCommand);
$("#loading_"+port+"_"+safeCommand).show();
$("#response_"+port+"_"+safeCommand).empty();
$.ajax({
url: 'launcher.php?type=sara&port='+port+'&command='+encodeURIComponent(command)+'&timeout='+timeout,
dataType:'text',
//dataType: 'json', // Specify that you expect a JSON response
method: 'GET', // Use GET or POST depending on your needs
success: function(response) {
//log response
console.log(response);
//hide spinning wheel
$("#loading_"+port+"_"+safeCommand).hide();
// si on fait le scan de network on veut une liste des réseaux
if (command == "AT+COPS=?") {
// Extract data within parentheses
const matches = response.match(/\(.*?\)/g); // Matches all `(...)` sections
const container = document.getElementById('table-network'); // Bootstrap container
// Check if matches exist
if (matches) {
const table = document.createElement('table');
table.className = 'table table-striped'; // Add Bootstrap table styling
const thead = document.createElement('thead');
const tbody = document.createElement('tbody');
// Table header (you can customize this based on your data)
const headerRow = document.createElement('tr');
const header1 = document.createElement('th');
header1.textContent = 'Status';
const header2 = document.createElement('th');
header2.textContent = 'Long oper';
const header3 = document.createElement('th');
header3.textContent = 'Short opeer';
const header4 = document.createElement('th');
header4.textContent = 'Numeric oper';
const header5 = document.createElement('th');
header5.textContent = 'AcT';
headerRow.appendChild(header1);
headerRow.appendChild(header2);
headerRow.appendChild(header3);
headerRow.appendChild(header4);
headerRow.appendChild(header5);
thead.appendChild(headerRow);
table.appendChild(thead);
// Loop through each match and create a row in the table
matches.forEach((item) => {
// Skip empty sections
if (item === "()") return;
const row = document.createElement('tr');
const values = item.slice(1, -1).split(','); // Remove parentheses and split by commas
// Add table cells (td) for each value
values.forEach((value) => {
const cell = document.createElement('td');
cell.textContent = value.trim(); // Remove extra spaces
row.appendChild(cell);
});
tbody.appendChild(row);
});
// Add tbody to table and append the table to the container
table.appendChild(tbody);
container.appendChild(table);
} else {
console.error('No valid data found in response.');
}
} else{
// si c'est une commande AT normale
// Replace newline characters with <br> tags
const formattedResponse = response.replace(/\n/g, "<br>")
.replace(/\b(OK)\b/g, '<span style="color: green; font-weight: bold;">$1</span>');;
$("#response_"+port+"_"+safeCommand).html(formattedResponse);
}
},
error: function(xhr, status, error) {
console.error('AJAX request failed:', status, error);
}
});
}
function connectNetwork_saraR4(port, networkID, timeout){
console.log(" Connect to network (port "+port+" and network id "+networkID+"):");
$("#loading_"+port+"_AT_COPS_Connect").show();
$.ajax({
url: 'launcher.php?type=sara_connectNetwork&port='+port+'&networkID='+encodeURIComponent(networkID)+'&timeout='+timeout,
dataType:'text',
//dataType: 'json', // Specify that you expect a JSON response
method: 'GET', // Use GET or POST depending on your needs
success: function(response) {
console.log(response);
$("#loading_"+port+"_AT_COPS_Connect").hide();
// Replace newline characters with <br> tags
const formattedResponse = response.replace(/\n/g, "<br>");
$("#response_"+port+"_AT_COPS_Connect").html(formattedResponse);
},
error: function(xhr, status, error) {
console.error('AJAX request failed:', status, error);
}
});
}
function setupServerHostname(port, serverName, timeout){
console.log(" Setupt server hostname "+serverName+"):");
$("#loading_serverHostname").show();
$.ajax({
url: 'launcher.php?type=sara_setupHostname&port='+port+'&networkID='+encodeURIComponent(serverName)+'&profileID=0',
dataType:'text',
//dataType: 'json', // Specify that you expect a JSON response
method: 'GET', // Use GET or POST depending on your needs
success: function(response) {
console.log(response);
$("#loading_serverHostname").hide();
// Replace newline characters with <br> tags
const formattedResponse = response.replace(/\n/g, "<br>");
$("#response_serverHostname").html(formattedResponse);
},
error: function(xhr, status, error) {
console.error('AJAX request failed:', status, error);
}
});
}
function mqtt_getConfig_saraR4(port, timeout){
console.log("GET MQTT config (port "+port+"):");
$("#loading_mqtt_getConfig").show();
$.ajax({
url: 'launcher.php?type=sara_getMQTT_config&port='+port+'&timeout='+timeout,
dataType:'text',
//dataType: 'json', // Specify that you expect a JSON response
method: 'GET', // Use GET or POST depending on your needs
success: function(response) {
console.log(response);
$("#loading_mqtt_getConfig").hide();
// Replace newline characters with <br> tags
const formattedResponse = response.replace(/\n/g, "<br>");
$("#response_mqtt_getConfig").html(formattedResponse);
},
error: function(xhr, status, error) {
console.error('AJAX request failed:', status, error);
}
});
}
function mqtt_login_logout(port, login_logout, timeout){
console.log("GET MQTT login / logout (port "+port+"):");
$("#loading_mqtt_login_logout").show();
$.ajax({
url: 'launcher.php?type=sara_getMQTT_login_logout&port='+port+'&login_logout='+login_logout+'&timeout='+timeout,
dataType:'text',
//dataType: 'json', // Specify that you expect a JSON response
method: 'GET', // Use GET or POST depending on your needs
success: function(response) {
console.log(response);
$("#loading_mqtt_login_logout").hide();
const formattedResponse = response.replace(/\n/g, "<br>");
$("#response_mqtt_login_logout").html(formattedResponse);
const regex = /^\+UMQTTC:\s*(\d+),(\d+)/m; // Match "+UMQTTC:", followed by two numbers separated by a comma
const match = response.match(regex);
if (match) {
const firstNumber = match[1]; // The first number after ":"
const secondNumber = match[2]; // The second number after the ","
if (firstNumber == 0) {
console.log("MQTT LOGOUT:");
$("#response_mqtt_login_logout").append("<p>logout</p>");
}
if (firstNumber == 1) {
console.log("MQTT LOGIN:");
$("#response_mqtt_login_logout").append("<p>login</p>");
}
if (secondNumber == 0) {
console.log("ERROR");
$("#response_mqtt_login_logout").append("<p>error</p>");
}
if (secondNumber == 1) {
console.log("SUCCESS");
$("#response_mqtt_login_logout").append("<p>success</p>");
}
} else {
console.log("No matching line found");
}
},
error: function(xhr, status, error) {
console.error('AJAX request failed:', status, error);
}
});
}
function mqtt_publish(port, message, timeout){
console.log(" MQTT publish (port "+port+"):");
$("#loading_mqtt_publish").show();
$.ajax({
url: 'launcher.php?type=sara_MQTT_publish&port='+port+'&timeout='+timeout+'&message='+message,
dataType: 'text',
//dataType: 'json', // Specify that you expect a JSON response
method: 'GET', // Use GET or POST depending on your needs
success: function(response) {
console.log(response);
$("#loading_mqtt_publish").hide();
// Replace newline characters with <br> tags
const formattedResponse = response.replace(/\n/g, "<br>");
$("#response_mqtt_publish").html(formattedResponse);
},
error: function(xhr, status, error) {
console.error('AJAX request failed:', status, error);
}
});
}
function setURL_saraR4(port, url){
console.log("Set URL for HTTP (port "+port+" and URL "+url+"):");
$("#loading_"+port+"_setURL").show();
$.ajax({
url: 'launcher.php?type=sara_setURL&port='+port+'&url='+encodeURIComponent(url),
dataType: 'text',
//dataType: 'json', // Specify that you expect a JSON response
method: 'GET', // Use GET or POST depending on your needs
success: function(response) {
console.log(response);
$("#loading_"+port+"_setURL").hide();
// Replace newline characters with <br> tags
const formattedResponse = response.replace(/\n/g, "<br>");
$("#response_"+port+"_setURL").html(formattedResponse);
},
error: function(xhr, status, error) {
console.error('AJAX request failed:', status, error);
}
});
}
function ping_test(port, url){
console.log("Test ping to data.nebuleair.fr:");
$("#response_ping").empty();
$("#loading_ping").show();
$.ajax({
url: 'launcher.php?type=sara_ping',
dataType: 'text',
//dataType: 'json', // Specify that you expect a JSON response
method: 'GET', // Use GET or POST depending on your needs
success: function(response) {
console.log(response);
$("#loading_ping").hide();
// Replace newline characters with <br> tags
const formattedResponse = response.replace(/\n/g, "<br>");
$("#response_ping").html(formattedResponse);
},
error: function(xhr, status, error) {
console.error('AJAX request failed:', status, error);
}
});
}
function PSD_setup(port, url){
console.log("Setup PSD connection:");
$("#loading_PSD").show();
$.ajax({
url: 'launcher.php?type=sara_psd_setup',
dataType: 'text',
//dataType: 'json', // Specify that you expect a JSON response
method: 'GET', // Use GET or POST depending on your needs
success: function(response) {
console.log(response);
$("#loading_PSD").hide();
// Replace newline characters with <br> tags
const formattedResponse = response.replace(/\n/g, "<br>");
$("#response_psd_setup").html(formattedResponse);
},
error: function(xhr, status, error) {
console.error('AJAX request failed:', status, error);
}
});
}
function writeMessage_saraR4(port, message, type){
console.log(type +" message to SARA R4 memory (port "+port+" and message "+message+"):");
$("#loading_"+port+"_message_write").show();
$.ajax({
url: 'launcher.php?type=sara_writeMessage&port='+port+'&message='+encodeURIComponent(message)+'&type2='+type,
dataType: 'text',
//dataType: 'json', // Specify that you expect a JSON response
method: 'GET', // Use GET or POST depending on your needs
success: function(response) {
console.log(response);
$("#loading_"+port+"_message_write").hide();
// Replace newline characters with <br> tags
const formattedResponse = response.replace(/\n/g, "<br>");
$("#response_"+port+"_message_write").html(formattedResponse);
},
error: function(xhr, status, error) {
console.error('AJAX request failed:', status, error);
}
});
}
function sendMessage_saraR4(port, endpoint){
console.log("Send message from SaraR4 (port "+port+" and endpoint "+endpoint+"):");
$("#loading_"+port+"_message_send").show();
$.ajax({
url: 'launcher.php?type=sara_sendMessage&port='+port+'&endpoint='+encodeURIComponent(endpoint),
dataType: 'text',
//dataType: 'json', // Specify that you expect a JSON response
method: 'GET', // Use GET or POST depending on your needs
success: function(response) {
console.log(response);
$("#loading_"+port+"_message_send").hide();
// Replace newline characters with <br> tags
const formattedResponse = response.replace(/\n/g, "<br>");
$("#response_"+port+"_message_send").html(formattedResponse);
},
error: function(xhr, status, error) {
console.error('AJAX request failed:', status, error);
}
});
}
function connectAPN_saraR4(port, APN_address, timeout){
console.log(" Set APN (port "+port+" and adress "+APN_address+"):");
$("#loading_"+port+"_APN").show();
$.ajax({
url: 'launcher.php?type=sara_APN&port='+port+'&APN_address='+encodeURIComponent(APN_address)+'&timeout='+timeout,
//dataType: 'json', // Specify that you expect a JSON response
dataType: 'text',
method: 'GET', // Use GET or POST depending on your needs
success: function(response) {
console.log(response);
$("#loading_"+port+"_APN").hide();
// Replace newline characters with <br> tags
const formattedResponse = response.replace(/\n/g, "<br>");
$("#response_"+port+"_APN").html(formattedResponse);
},
error: function(xhr, status, error) {
console.error('AJAX request failed:', status, error);
}
});
}
function getModem_busy_status() {
//console.log("Getting modem busy status");
const SARA_busy_message = document.getElementById("modem_status_message");
$.ajax({
url: 'launcher.php?type=getModem_busy',
dataType: 'json', // Expecting JSON response
method: 'GET',
success: function(response) {
//console.log(response);
if (response.running) {
// Script is running → Red button, "Modem is busy"
SARA_busy_message.innerHTML= ` <div class="alert alert-warning" role="alert">
Le modem 4G est en cours d'utilisation! L'utilisation des boutons ci-dessous peut entrainer des erreurs. Veuillez mettre le modem en mode configuration.
</div>`
} else {
// Script is NOT running → Green button, "Modem is available"
SARA_busy_message.innerHTML= ` <div class="alert alert-primary" role="alert">
Veuillez vous assurer de mettre le modem en mode configuration avant de cliquer sur les boutons ci-dessous. <br>
Une fois terminé veillez à bien désactiver le mode configuration.
</div>`
}
},
error: function(xhr, status, error) {
console.error('AJAX request failed:', status, error);
SARA_busy_status.textContent = "Error checking status";
SARA_busy_status.className = "btn text-bg-warning"; // Yellow button for errors
}
});
}
function update_modem_configMode(param, checked){
//change ('modem_config_mode', '0', 'bool') inside SQLITE db
// response type: {"success":true,"message":"Configuration updated successfully","param":"modem_config_mode","value":"0","type":"bool"}
const toastLiveExample = document.getElementById('liveToast')
const toastBody = toastLiveExample.querySelector('.toast-body');
console.log("updating modem config mode to :" + checked);
$.ajax({
url: 'launcher.php?type=update_config_sqlite&param='+param+'&value='+checked,
dataType: 'json', // Specify that you expect a JSON response
method: 'GET', // Use GET or POST depending on your needs
cache: false, // Prevent AJAX from caching
success: function(response) {
console.log("AJAX success:");
console.log(response);
// Format the response nicely
let formattedMessage = '';
if (response.success) {
// Success message
toastLiveExample.classList.remove('text-bg-danger');
toastLiveExample.classList.add('text-bg-success');
formattedMessage = `
<strong>Success!</strong><br>
Parameter: ${response.param || param}<br>
Value: ${response.value || checked}<br>
${response.message || ''}
`;
} else {
// Error message
toastLiveExample.classList.remove('text-bg-success');
toastLiveExample.classList.add('text-bg-danger');
formattedMessage = `
<strong>Error!</strong><br>
${response.error || 'Unknown error'}<br>
Parameter: ${response.param || param}
`;
}
// Update the toast body with formatted content
toastBody.innerHTML = formattedMessage;
// Show the toast
const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample)
toastBootstrap.show()
},
error: function(xhr, status, error) {
console.error('AJAX request failed:', status, error);
// Update toast with error message
toastBody.textContent = 'Error: ' + error;
// Set toast to danger color
toastLiveExample.classList.remove('text-bg-success');
toastLiveExample.classList.add('text-bg-danger');
// Show the toast for errors too
const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample);
toastBootstrap.show();
}
});
}
</script>
</body>
</html>