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>
948 lines
41 KiB
HTML
Executable File
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¶m='+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>
|