1235 lines
53 KiB
HTML
Executable File
1235 lines
53 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 Pro</title>
|
|
<!-- Link Bootstrap CSS locally -->
|
|
<link rel="stylesheet" href="html/assets/css/bootstrap.min.css">
|
|
<style>
|
|
|
|
.deviceID {
|
|
margin-top: 2px; /* Add some top margin for spacing */
|
|
font-size: 1.5rem; /* Adjust the font size */
|
|
color: #33577c; /* Bootstrap primary color */
|
|
text-align: center;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<nav class="navbar bg-body-tertiary">
|
|
<div class="container-fluid d-flex justify-content-between align-items-center">
|
|
<!-- Texte aligné à gauche -->
|
|
|
|
<a class="navbar-brand" href="#">
|
|
<img src="html/assets/img/LogoNebuleAir.png" alt="Logo" height="30" class="d-inline-block align-text-top">
|
|
</a>
|
|
<!-- Texte centré au milieu -->
|
|
<div class="mx-auto text-center">
|
|
<span id="pageTitle_plus_ID">Texte au milieu</span>
|
|
</div>
|
|
|
|
|
|
<!-- Texte à droite -->
|
|
<div class="text-end">
|
|
<button type="button" class="btn btn-outline-secondary" id="RTC_time">loading...</button>
|
|
</div>
|
|
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="container">
|
|
|
|
|
|
<h3>Capteurs</h3>
|
|
|
|
<!-- NEXT PM & I2C sound -->
|
|
<div class="row mb-3" id="card-container"></div>
|
|
|
|
<h3>
|
|
Modem 4G status
|
|
<span id="modem-status" class="badge">Loading...</span>
|
|
</h3>
|
|
|
|
<div class="row mb-3">
|
|
|
|
<div class="col-sm-4">
|
|
<div class="card">
|
|
|
|
<div class="card-body">
|
|
<p class="card-text">General information. </p>
|
|
<button class="btn btn-primary" onclick="getData_saraR4('ttyAMA2', 'ATI', 2)">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-4">
|
|
<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?', 2)">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-4">
|
|
<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>
|
|
|
|
<h3>Connexion 4G Network</h3>
|
|
<div class="row mb-3">
|
|
|
|
<div class="col-sm-8">
|
|
<div class="card text-dark bg-light">
|
|
|
|
<div class="card-body">
|
|
<p class="card-text">Network scan. Attention: 2 min scan.</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-4">
|
|
<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>
|
|
|
|
<h3>MQTT</h3>
|
|
<div class="row mb-3">
|
|
<!-- Get CONFIG -->
|
|
<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>
|
|
|
|
<!-- MQTT LOGIN -->
|
|
|
|
<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>
|
|
|
|
<!-- Send MESSAGE -->
|
|
|
|
<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>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>
|
|
|
|
<!-- WIFI -->
|
|
<h3>WIFI status
|
|
<span id="wifi-status" class="badge">Loading...</span>
|
|
</h3>
|
|
|
|
<div class="row mb-3">
|
|
|
|
<div class="col-sm-4">
|
|
<div class="card text-dark bg-light">
|
|
<div class="card-body">
|
|
<h5 class="card-title">WIFI / Ethernet</h5>
|
|
<p class="card-text">General information.</p>
|
|
<button class="btn btn-primary" onclick="get_internet()">Get Data</button>
|
|
<table class="table table-striped-columns">
|
|
<tbody id="data-table-body_internet_general"></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-sm-8">
|
|
<div class="card text-dark bg-light">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Wifi Scan</h5>
|
|
<p class="card-text">Scan des réseaux WIFI disponibles.</p>
|
|
<button class="btn btn-primary" onclick="wifi_scan()">Scan</button>
|
|
<table class="table">
|
|
<tbody id="data-table-body_wifi_scan"></tbody>
|
|
</table>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<!-- Modal WIFI PASSWORD -->
|
|
<!-- filled with JS -->
|
|
<div class="modal fade" id="myModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h1 class="modal-title fs-5" id="myModalLabel">Modal title</h1>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body" id="myModalBody">
|
|
...
|
|
</div>
|
|
<div class="modal-footer" id="myModalFooter">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
<button type="button" class="btn btn-primary">Save changes</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!--
|
|
<div class="col-sm-4">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h5 class="card-title">WIFI Connect</h5>
|
|
<p class="card-text">Connect to WIFI.</p>
|
|
<form action="launcher.php" method="get" onsubmit="return confirmSubmit()">
|
|
<div class="mb-3">
|
|
<label for="SSID_" class="form-label">SSID</label>
|
|
<input type="text" name="SSID" class="form-control" id="SSID_" aria-describedby="emailHelp">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="exampleInputPassword1" class="form-label">Password</label>
|
|
<input type="password" name="pass" class="form-control" id="exampleInputPassword1">
|
|
</div>
|
|
<input type="hidden" name="type" value="wifi_connect">
|
|
|
|
<button type="submit" class="btn btn-primary">Submit</button>
|
|
</form>
|
|
|
|
<div id="response_hotspot_status"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
-->
|
|
<!--
|
|
<div class="col-sm-4">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h5 class="card-title">WIFI Hotspot</h5>
|
|
<p class="card-text">Check if wifi Hotspot (AP) is activated.</p>
|
|
<button class="btn btn-primary" onclick="get_hotspot_status()">Check</button>
|
|
<div id="response_hotspot_status"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
-->
|
|
</div>
|
|
<!-- end row -->
|
|
|
|
<h3>Logs</h3>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-sm-4">
|
|
|
|
<!-- Button trigger modal -->
|
|
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#bootLog_modal">
|
|
Boot Logs
|
|
</button>
|
|
|
|
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#loopLog_modal">
|
|
Loop Logs
|
|
</button>
|
|
|
|
<!-- Modal Boot Logs -->
|
|
<div class="modal fade" id="bootLog_modal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-xl">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h1 class="modal-title fs-5" id="exampleModalLabel">Boot logs</h1>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<pre id="log-content" style="white-space: pre-wrap; word-wrap: break-word;"></pre>
|
|
|
|
...
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
<button type="button" class="btn btn-primary" id="refreshBootLog">Refresh</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal Loop Logs -->
|
|
<div class="modal fade" id="loopLog_modal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-xl">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h1 class="modal-title fs-5" id="exampleModalLabel">Loop logs</h1>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
...
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
<button type="button" class="btn btn-primary" id="refreshLoopLog">Refresh</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
<!-- end row -->
|
|
|
|
|
|
<h3>Admin</h3>
|
|
<div class="row mb-3">
|
|
<div class="col-sm-10">
|
|
<button type="button" class="btn btn-danger" onclick="rebootDevice()">
|
|
Reboot
|
|
</button>
|
|
<button type="button" class="btn btn-info" onclick="startSSHTunnel()">
|
|
Start SSH Tunnel
|
|
</button>
|
|
<button type="button" id="updateButton" class="btn btn-success" onclick="updateGitPull()">
|
|
Update
|
|
</button>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
<!-- end container -->
|
|
|
|
</body>
|
|
|
|
|
|
|
|
<!-- JAVASCRIPT -->
|
|
|
|
<!-- Link Ajax locally -->
|
|
<script src="html/assets/jquery/jquery-3.7.1.min.js"></script>
|
|
<!-- Link Bootstrap JS and Popper.js locally -->
|
|
<script src="html/assets/js/bootstrap.bundle.js"></script>
|
|
|
|
<script>
|
|
|
|
|
|
function updateGitPull(){
|
|
console.log("Updating device (git pull)");
|
|
|
|
$.ajax({
|
|
url: 'launcher.php?type=git_pull',
|
|
method: 'GET', // Use GET or POST depending on your needs
|
|
success: function(response) {
|
|
// Handle success response if needed
|
|
console.log(response);
|
|
alert(response);
|
|
// Reload the page after the device update
|
|
location.reload(); // This will reload the page
|
|
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('AJAX request failed:', status, error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function startSSHTunnel(){
|
|
console.log("Will start ssh tunnel");
|
|
console.log("need to retreive ssh port");
|
|
|
|
fetch('config.json') // Replace 'deviceID.txt' with 'config.json'
|
|
.then(response => response.json()) // Parse response as JSON
|
|
.then(data => {
|
|
//get device ID
|
|
const deviceSSH_port = data.sshTunnel_port
|
|
console.log("Device SSH port retrieved: " + deviceSSH_port);
|
|
startSSHTunnel_2(deviceSSH_port);
|
|
|
|
})
|
|
.catch(error => {
|
|
console.error('Error retrieving device ssh port:', error);
|
|
alert('An error occurred while fetching the device ID.');
|
|
});
|
|
}
|
|
|
|
function startSSHTunnel_2(deviceSSH_port){
|
|
$.ajax({
|
|
url: 'launcher.php?type=sshTunnel&ssh_port='+deviceSSH_port,
|
|
method: 'GET', // Use GET or POST depending on your needs
|
|
success: function(response) {
|
|
// Handle success response if needed
|
|
console.log(response);
|
|
alert("Tunnel started");
|
|
|
|
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('AJAX request failed:', status, error);
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
|
|
function rebootDevice(){
|
|
console.log("Will reboot system");
|
|
var userConfirmed = confirm("Are you sure you want to reboot the system? If so, press ok and wait few seconds before reloading page.");
|
|
|
|
if (userConfirmed) {
|
|
$.ajax({
|
|
url: 'launcher.php?type=reboot',
|
|
method: 'GET', // Use GET or POST depending on your needs
|
|
success: function(response) {
|
|
// Handle success response if needed
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('AJAX request failed:', status, error);
|
|
}
|
|
});
|
|
} else {
|
|
console.log("Reboot canceled.");
|
|
}
|
|
}
|
|
|
|
function getNPM_values(port){
|
|
console.log("Data from NPM (port "+port+"):");
|
|
$("#loading_"+port).show();
|
|
|
|
$.ajax({
|
|
url: 'launcher.php?type=npm&port='+port,
|
|
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);
|
|
const tableBody = document.getElementById("data-table-body_"+port);
|
|
tableBody.innerHTML = "";
|
|
|
|
$("#loading_"+port).hide();
|
|
// Create an array of the desired keys
|
|
const keysToShow = ["PM1", "PM25", "PM10"];
|
|
// Add only the specified elements to the table
|
|
keysToShow.forEach(key => {
|
|
if (response[key] !== undefined) { // Check if the key exists in the response
|
|
const value = response[key];
|
|
$("#data-table-body_"+port).append(`
|
|
<tr>
|
|
<td>${key}</td>
|
|
<td>${value} µg/m³</td>
|
|
</tr>
|
|
`);
|
|
}
|
|
});
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('AJAX request failed:', status, error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function getNoise_values(){
|
|
console.log("Data from I2C Noise Sensor:");
|
|
$("#loading_noise").show();
|
|
|
|
$.ajax({
|
|
url: 'launcher.php?type=noise',
|
|
method: 'GET', // Use GET or POST depending on your needs
|
|
success: function(response) {
|
|
console.log(response);
|
|
const tableBody = document.getElementById("data-table-body_noise");
|
|
tableBody.innerHTML = "";
|
|
$("#loading_noise").hide();
|
|
|
|
// Create an array of the desired keys
|
|
const keysToShow = ["Noise"];
|
|
// Add only the specified elements to the table
|
|
keysToShow.forEach(key => {
|
|
if (response !== undefined) { // Check if the key exists in the response
|
|
const value = response;
|
|
$("#data-table-body_noise").append(`
|
|
<tr>
|
|
<td>${key}</td>
|
|
<td>${value} DB</td>
|
|
</tr>
|
|
`);
|
|
}
|
|
});
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('AJAX request failed:', status, error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function getBME280_values(){
|
|
console.log("Data from I2C BME280:");
|
|
$("#loading_BME280").show();
|
|
|
|
$.ajax({
|
|
url: 'launcher.php?type=BME280',
|
|
method: 'GET', // Use GET or POST depending on your needs
|
|
success: function(response) {
|
|
console.log(response);
|
|
|
|
const tableBody = document.getElementById("data-table-body_BME280");
|
|
tableBody.innerHTML = "";
|
|
$("#loading_BME280").hide();
|
|
|
|
// Parse the JSON response
|
|
const data = JSON.parse(response);
|
|
const keysToShow = ["temp", "hum", "press"];
|
|
|
|
|
|
// Add only the specified elements to the table
|
|
keysToShow.forEach(key => {
|
|
if (response !== undefined) { // Check if the key exists in the response
|
|
const value = data[key];
|
|
const unit = key === "temp" ? "°C"
|
|
: key === "hum" ? "%"
|
|
: key === "press" ? "hPa"
|
|
: ""; // Add appropriate units
|
|
|
|
$("#data-table-body_BME280").append(`
|
|
<tr>
|
|
<td>${key.charAt(0).toUpperCase() + key.slice(1)}</td>
|
|
<td>${value} ${unit}</td>
|
|
</tr>
|
|
`);
|
|
}
|
|
});
|
|
},
|
|
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();
|
|
|
|
$.ajax({
|
|
url: 'launcher.php?type=sara&port='+port+'&command='+encodeURIComponent(command)+'&timeout='+timeout,
|
|
//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>");
|
|
$("#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: '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 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: '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: '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: '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: '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 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: '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: '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 get_internet(){
|
|
console.log("Getting internet general infos");
|
|
$.ajax({
|
|
url: 'launcher.php?type=internet',
|
|
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);
|
|
let tableBody = document.getElementById('data-table-body_internet_general');
|
|
tableBody.innerHTML = ''; // Clear existing table content
|
|
|
|
// Iterate through the data and create rows
|
|
for (let key in response) {
|
|
let row = `
|
|
<tr>
|
|
<td>${key}</td>
|
|
<td>${response[key].connection}</td>
|
|
<td>${response[key].IP ? response[key].IP : "No IP"}</td>
|
|
</tr>
|
|
`;
|
|
tableBody.innerHTML += row; // Append row to table body
|
|
}
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('AJAX request failed:', status, error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function wifi_connect(SSID, PASS){
|
|
console.log("Connecting to wifi");
|
|
console.log(SSID);
|
|
console.log(PASS);
|
|
if (typeof PASS === 'undefined') {
|
|
console.log("Need to add password");
|
|
//open bootstrap modal to ask for password
|
|
var myModal = new bootstrap.Modal(document.getElementById('myModal'));
|
|
//modifiy modal title
|
|
document.getElementById('myModalLabel').innerHTML = "Enter password for "+SSID;
|
|
//add input field to modal body
|
|
document.getElementById('myModalBody').innerHTML = "<input type='text' id='wifi_pass' class='form-control' placeholder='Password'>";
|
|
//add button to modal footer
|
|
document.getElementById('myModalFooter').innerHTML = "<button type='button' class='btn btn-secondary' data-bs-dismiss='modal'>Close</button><button type='button' class='btn btn-primary' onclick='wifi_connect(\""+SSID+"\", document.getElementById(\"wifi_pass\").value)'>Se connecter</button>";
|
|
myModal.show();
|
|
} else {
|
|
console.log("Will try to connect to "+SSID+" with password "+PASS);
|
|
console.log("Start PHP script:");
|
|
|
|
$.ajax({
|
|
url: 'launcher.php?type=wifi_connect&SSID='+SSID+'&pass='+PASS,
|
|
dataType: 'text', // Specify that you expect a JSON response
|
|
method: 'GET', // Use GET or POST depending on your needs
|
|
success: function(response) {
|
|
console.log(response);
|
|
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('AJAX request failed:', status, error);
|
|
}
|
|
});
|
|
|
|
}
|
|
}
|
|
|
|
function wifi_scan(){
|
|
console.log("Scanning Wifi");
|
|
$.ajax({
|
|
url: 'launcher.php?type=wifi_scan',
|
|
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);
|
|
const tableBody = document.getElementById("data-table-body_wifi_scan");
|
|
|
|
// Clear the existing table body
|
|
tableBody.innerHTML = "";
|
|
|
|
// Loop through the wifiNetworks array and create rows
|
|
response.forEach(network => {
|
|
const row = document.createElement("tr");
|
|
|
|
// Create and append cells for SSID, BARS, and SIGNAL
|
|
const ssidCell = document.createElement("td");
|
|
// Truncate SSID to 25 characters
|
|
const truncatedSSID = network.SSID.length > 20 ? network.SSID.substring(0, 20) + '...' : network.SSID;
|
|
ssidCell.textContent = truncatedSSID;
|
|
row.appendChild(ssidCell);
|
|
|
|
/*
|
|
const signalCell = document.createElement("td");
|
|
signalCell.textContent = network.SIGNAL;
|
|
row.appendChild(signalCell);
|
|
*/
|
|
|
|
// Create a button
|
|
const buttonCell = document.createElement("td");
|
|
const button = document.createElement("button");
|
|
button.textContent = "Connect"; // Button text
|
|
button.classList.add("btn", "btn-primary"); // Bootstrap button classes
|
|
|
|
// Determine button color based on SIGNAL value
|
|
const signalValue = parseInt(network.SIGNAL, 10); // Assuming SIGNAL is a numeric value
|
|
// Calculate color based on the signal strength
|
|
let buttonColor;
|
|
if (signalValue >= 100) {
|
|
buttonColor = "success"; // Green for strong signal
|
|
} else if (signalValue >= 50) {
|
|
buttonColor = "warning"; // Yellow for moderate signal
|
|
} else {
|
|
buttonColor = "danger"; // Red for weak signal
|
|
}
|
|
// Add Bootstrap button classes along with color
|
|
button.classList.add("btn", `btn-${buttonColor}`);
|
|
|
|
|
|
//Trigger function as soon as the button is clicked
|
|
button.addEventListener("click", () => wifi_connect(network.SSID));
|
|
|
|
|
|
// Append the button to the button cell
|
|
buttonCell.appendChild(button);
|
|
row.appendChild(buttonCell);
|
|
|
|
// Append the row to the table body
|
|
tableBody.appendChild(row);
|
|
});
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('AJAX request failed:', status, error);
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
function confirmSubmit() {
|
|
// You can display a simple confirmation message or customize the behavior
|
|
return confirm("Are you sure you want to connect to this Wi-Fi network?");
|
|
}
|
|
|
|
let intervalId;
|
|
|
|
function startNoise() {
|
|
// Check if interval is already running
|
|
if (!intervalId) {
|
|
intervalId = setInterval(getNoise_values, 1000);
|
|
console.log("Function started");
|
|
}
|
|
}
|
|
|
|
function stopNoise() {
|
|
if (intervalId) {
|
|
clearInterval(intervalId);
|
|
intervalId = null; // Reset intervalId to indicate that the function is stopped
|
|
console.log("Function stopped");
|
|
}
|
|
}
|
|
//setInterval(getNoise_values, 1000);
|
|
|
|
window.onload = function() {
|
|
fetch('config.json') // Replace 'deviceID.txt' with 'config.json'
|
|
.then(response => response.json()) // Parse response as JSON
|
|
.then(data => {
|
|
//get device ID
|
|
const deviceID = data.deviceID.trim().toUpperCase();
|
|
document.getElementById('pageTitle_plus_ID').innerText = 'token: ' + deviceID;
|
|
|
|
//get SARA_R4 connection status
|
|
const SARA_statusElement = document.getElementById("modem-status");
|
|
console.log("SARA R4 is: " + data.SARA_R4_network_status);
|
|
|
|
if (data.SARA_R4_network_status === "connected") {
|
|
SARA_statusElement.textContent = "Connected";
|
|
SARA_statusElement.className = "badge text-bg-success";
|
|
} else if (data.SARA_R4_network_status === "disconnected") {
|
|
SARA_statusElement.textContent = "Disconnected";
|
|
SARA_statusElement.className = "badge text-bg-danger";
|
|
} else {
|
|
SARA_statusElement.textContent = "Unknown";
|
|
SARA_statusElement.className = "badge text-bg-secondary";
|
|
}
|
|
|
|
//get wifi connection status
|
|
const WIFI_statusElement = document.getElementById("wifi-status");
|
|
console.log("WIFI is: " + data.WIFI_status);
|
|
|
|
if (data.WIFI_status === "connected") {
|
|
WIFI_statusElement.textContent = "Connected";
|
|
WIFI_statusElement.className = "badge text-bg-success";
|
|
} else if (data.WIFI_status === "hotspot") {
|
|
WIFI_statusElement.textContent = "Hotspot";
|
|
WIFI_statusElement.className = "badge text-bg-warning";
|
|
} else {
|
|
WIFI_statusElement.textContent = "Unknown";
|
|
WIFI_statusElement.className = "badge text-bg-secondary";
|
|
}
|
|
|
|
//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);
|
|
}
|
|
});
|
|
|
|
const container = document.getElementById('card-container'); // Conteneur des cartes
|
|
//creates NPM cards
|
|
const ports = data.NextPM_ports; // Récupère les ports
|
|
|
|
// Générer les cartes dynamiquement
|
|
ports.forEach((port, index) => {
|
|
const cardHTML = `
|
|
<div class="col-sm-3">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
Port UART ${port.replace('ttyAMA', '')}
|
|
</div>
|
|
<div class="card-body">
|
|
<h5 class="card-title">NextPM ${String.fromCharCode(65 + index)}</h5>
|
|
<p class="card-text">Capteur particules fines.</p>
|
|
<button class="btn btn-primary" onclick="getNPM_values('${port}')">Get Data</button>
|
|
<div id="loading_${port}" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
|
|
<table class="table table-striped-columns">
|
|
<tbody id="data-table-body_${port}"></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>`;
|
|
container.innerHTML += cardHTML; // Ajouter la carte au conteneur
|
|
});
|
|
|
|
//creates i2c BME280 card
|
|
if (data.i2c_BME) {
|
|
const i2C_BME_HTML = `
|
|
<div class="col-sm-3">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
Port I2C
|
|
</div>
|
|
<div class="card-body">
|
|
<h5 class="card-title">BME280 Temp/Hum sensor</h5>
|
|
<p class="card-text">Capteur température et humidité sur le port I2C.</p>
|
|
<button class="btn btn-primary mb-1" onclick="getBME280_values()">Get Data</button>
|
|
<br>
|
|
<div id="loading_BME280" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
|
|
<table class="table table-striped-columns">
|
|
<tbody id="data-table-body_BME280"></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>`;
|
|
|
|
container.innerHTML += i2C_BME_HTML; // Add the I2C card if condition is met
|
|
}
|
|
|
|
//creates i2c sound card
|
|
if (data.i2C_sound) {
|
|
const i2C_HTML = `
|
|
<div class="col-sm-3">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
Port I2C
|
|
</div>
|
|
<div class="card-body">
|
|
<h5 class="card-title">Decibel Meter</h5>
|
|
<p class="card-text">Capteur bruit sur le port I2C.</p>
|
|
<button class="btn btn-primary mb-1" onclick="getNoise_values()">Get Data</button>
|
|
<br>
|
|
<button class="btn btn-success" onclick="startNoise()">Start recording</button>
|
|
<button class="btn btn-danger" onclick="stopNoise()">Stop recording</button>
|
|
<div id="loading_noise" class="spinner-border spinner-border-sm" style="display: none;" role="status"></div>
|
|
<table class="table table-striped-columns">
|
|
<tbody id="data-table-body_noise"></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>`;
|
|
|
|
container.innerHTML += i2C_HTML; // Add the I2C card if condition is met
|
|
}
|
|
|
|
})
|
|
.catch(error => console.error('Error loading config.json:', error));
|
|
}
|
|
|
|
|
|
// LOGS modal
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
// Get the modal body
|
|
const modal_loop_Body = document.querySelector('#loopLog_modal .modal-body');
|
|
const modal_boot_Body = document.querySelector('#bootLog_modal .modal-body');
|
|
|
|
// LOOP
|
|
function fetchLoopLogs() {
|
|
fetch('logs/loop.log')
|
|
.then((response) => {
|
|
if (!response.ok) {
|
|
throw new Error('Failed to fetch the log file.');
|
|
}
|
|
return response.text();
|
|
})
|
|
.then((data) => {
|
|
const lines = data.split('\n');
|
|
|
|
// Format log content
|
|
const formattedLog = lines
|
|
.map((line) => line.trim()) // Remove extra whitespace
|
|
.filter((line) => line) // Remove empty lines
|
|
.join('<br>'); // Join formatted lines with line breaks
|
|
|
|
modal_loop_Body.innerHTML = `<pre style="white-space: pre-wrap; word-wrap: break-word; margin: 0;">${formattedLog}</pre>`;
|
|
})
|
|
.catch((error) => {
|
|
console.error(error);
|
|
modal_loop_Body.textContent = 'Error loading log file.';
|
|
});
|
|
}
|
|
//BOOT
|
|
function fetchBootLogs() {
|
|
fetch('logs/app.log')
|
|
.then((response) => {
|
|
if (!response.ok) {
|
|
throw new Error('Failed to fetch the log file.');
|
|
}
|
|
return response.text();
|
|
})
|
|
.then((data) => {
|
|
const lines = data.split('\n');
|
|
|
|
// Format log content
|
|
const formattedLog = lines
|
|
.map((line) => line.trim()) // Remove extra whitespace
|
|
.filter((line) => line) // Remove empty lines
|
|
.join('<br>'); // Join formatted lines with line breaks
|
|
|
|
modal_boot_Body.innerHTML = `<pre style="white-space: pre-wrap; word-wrap: break-word; margin: 0;">${formattedLog}</pre>`;
|
|
})
|
|
.catch((error) => {
|
|
console.error(error);
|
|
modal_boot_Body.textContent = 'Error loading log file.';
|
|
});
|
|
}
|
|
|
|
document.getElementById('loopLog_modal').addEventListener('show.bs.modal', fetchLoopLogs);
|
|
document.getElementById('refreshLoopLog').addEventListener('click', fetchLoopLogs);
|
|
|
|
document.getElementById('bootLog_modal').addEventListener('show.bs.modal', fetchBootLogs);
|
|
document.getElementById('refreshBootLog').addEventListener('click', fetchBootLogs);
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
</script>
|
|
</html> |