491 lines
21 KiB
HTML
Executable File
491 lines
21 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">Connection WIFI</h1>
|
|
<p>La connexion WIFI n'est pas obligatoire mais elle vous permet d'effectuer des mises à jour et d'activer le contrôle à distance.</p>
|
|
|
|
<h3>Status
|
|
<span id="wifi-status" class="badge">Loading...</span>
|
|
<button id="btn-forget-wifi" class="btn btn-outline-danger btn-sm ms-2" style="display:none;" onclick="wifi_forget()">Oublier le réseau</button>
|
|
</h3>
|
|
|
|
<div class="row mb-3">
|
|
|
|
<!-- Connection Info Card (shown when connected to WiFi) -->
|
|
<div class="col-sm-6" id="card-connection-info" style="display:none;">
|
|
<div class="card border-success">
|
|
<div class="card-header bg-success text-white">
|
|
<h5 class="card-title mb-0">Connexion WiFi</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="connection-info-loading" class="text-center py-3">
|
|
<div class="spinner-border spinner-border-sm text-primary" role="status"></div>
|
|
<span class="ms-2">Chargement...</span>
|
|
</div>
|
|
<table class="table table-sm mb-0" id="connection-info-table" style="display:none;">
|
|
<tbody>
|
|
<tr><td class="text-muted" style="width:40%">SSID</td><td><strong id="info-ssid">-</strong></td></tr>
|
|
<tr><td class="text-muted">Signal</td><td><span id="info-signal">-</span></td></tr>
|
|
<tr><td class="text-muted">Adresse IP</td><td><code id="info-ip">-</code></td></tr>
|
|
<tr><td class="text-muted">Passerelle</td><td><code id="info-gateway">-</code></td></tr>
|
|
<tr><td class="text-muted">Hostname</td><td><code id="info-hostname">-</code></td></tr>
|
|
<tr><td class="text-muted">Frequence</td><td id="info-freq">-</td></tr>
|
|
<tr><td class="text-muted">Securite</td><td id="info-security">-</td></tr>
|
|
</tbody>
|
|
</table>
|
|
<button class="btn btn-outline-primary btn-sm mt-2" onclick="get_internet()">Rafraichir</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Ethernet Card -->
|
|
<div class="col-sm-6" id="card-ethernet">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">Ethernet</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<table class="table table-sm mb-0">
|
|
<tbody>
|
|
<tr><td class="text-muted" style="width:40%">Etat</td><td id="info-eth-status">-</td></tr>
|
|
<tr><td class="text-muted">Adresse IP</td><td><code id="info-eth-ip">-</code></td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Hotspot Info Card (shown when in hotspot mode) -->
|
|
<div class="col-sm-6" id="card-hotspot-info" style="display:none;">
|
|
<div class="card border-warning">
|
|
<div class="card-header bg-warning">
|
|
<h5 class="card-title mb-0">Mode Hotspot</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="mb-1">Le capteur n'est connecte a aucun reseau WiFi.</p>
|
|
<p class="text-muted mb-0">Utilisez le scan ci-dessous pour vous connecter a un reseau.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- WiFi Scan Card (hidden when connected) -->
|
|
<div class="row mb-3" id="card-wifi-scan" style="display:none;">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h5 class="card-title mb-0">Reseaux WiFi disponibles</h5>
|
|
<button class="btn btn-primary btn-sm" onclick="wifi_scan()">Scan</button>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="wifi-scan-cache-notice" class="alert alert-info py-2 mb-2" style="display:none; font-size: 0.85rem;">
|
|
Scan effectue au demarrage du capteur (scan live indisponible en mode hotspot).
|
|
</div>
|
|
<div id="wifi-scan-empty" class="text-center text-muted py-3">
|
|
Cliquez sur "Scan" pour rechercher les reseaux WiFi.
|
|
</div>
|
|
<table class="table table-hover mb-0" id="wifi-scan-table" style="display:none;">
|
|
<thead>
|
|
<tr><th>SSID</th><th>Signal</th><th>Securite</th><th></th></tr>
|
|
</thead>
|
|
<tbody id="data-table-body_wifi_scan"></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal WIFI PASSWORD -->
|
|
<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>
|
|
|
|
</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 src="assets/js/topbar-logo.js"></script>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
console.log("DOMContentLoaded");
|
|
|
|
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));
|
|
});
|
|
});
|
|
|
|
function getSignalBadge(signal) {
|
|
const val = parseInt(signal, 10);
|
|
if (isNaN(val)) return '';
|
|
let color, label;
|
|
if (val >= 70) { color = 'success'; label = 'Excellent'; }
|
|
else if (val >= 50) { color = 'primary'; label = 'Bon'; }
|
|
else if (val >= 30) { color = 'warning'; label = 'Faible'; }
|
|
else { color = 'danger'; label = 'Tres faible'; }
|
|
return `<span class="badge text-bg-${color}">${val}% — ${label}</span>`;
|
|
}
|
|
|
|
function get_internet(){
|
|
console.log("Getting internet general infos");
|
|
document.getElementById('connection-info-loading').style.display = '';
|
|
document.getElementById('connection-info-table').style.display = 'none';
|
|
|
|
$.ajax({
|
|
url: 'launcher.php?type=internet',
|
|
dataType: 'json',
|
|
method: 'GET',
|
|
success: function(response) {
|
|
console.log(response);
|
|
const wifi = response.wifi;
|
|
const eth = response.ethernet;
|
|
|
|
document.getElementById('info-ssid').textContent = wifi.ssid || '-';
|
|
document.getElementById('info-signal').innerHTML = wifi.signal ? getSignalBadge(wifi.signal) : '-';
|
|
document.getElementById('info-ip').textContent = wifi.IP || '-';
|
|
document.getElementById('info-gateway').textContent = wifi.gateway || '-';
|
|
document.getElementById('info-hostname').textContent = wifi.hostname || '-';
|
|
document.getElementById('info-freq').textContent = wifi.frequency ? wifi.frequency + ' MHz' : '-';
|
|
document.getElementById('info-security').textContent = wifi.security || '-';
|
|
|
|
document.getElementById('info-eth-status').textContent = eth.connection || '-';
|
|
document.getElementById('info-eth-ip').textContent = eth.IP || '-';
|
|
|
|
document.getElementById('connection-info-loading').style.display = 'none';
|
|
document.getElementById('connection-info-table').style.display = '';
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('AJAX request failed:', status, error);
|
|
document.getElementById('connection-info-loading').innerHTML = '<span class="text-danger">Erreur de chargement</span>';
|
|
}
|
|
});
|
|
}
|
|
|
|
function wifi_connect(SSID, PASS){
|
|
console.log("Connecting to wifi");
|
|
if (typeof PASS === 'undefined') {
|
|
var myModal = new bootstrap.Modal(document.getElementById('myModal'));
|
|
document.getElementById('myModalLabel').innerHTML = "Enter password for "+SSID;
|
|
document.getElementById('myModalBody').innerHTML = "<input type='text' id='wifi_pass' class='form-control' placeholder='Password'>";
|
|
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 {
|
|
var myModal = bootstrap.Modal.getInstance(document.getElementById('myModal'));
|
|
if (myModal) { myModal.hide(); }
|
|
|
|
$.ajax({
|
|
url: 'launcher.php?type=wifi_connect&SSID='+SSID+'&pass='+PASS,
|
|
dataType: 'json',
|
|
method: 'GET',
|
|
success: function(response) {
|
|
console.log(response);
|
|
showConnectionStatus(response);
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('AJAX request failed:', status, error);
|
|
alert('Error: Could not start connection process');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function showConnectionStatus(response) {
|
|
const lang = localStorage.getItem('language') || 'fr';
|
|
const instructions = response.instructions[lang] || response.instructions['fr'];
|
|
|
|
const overlay = document.createElement('div');
|
|
overlay.id = 'connection-status-overlay';
|
|
overlay.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.9);z-index:9999;display:flex;align-items:center;justify-content:center;color:white;';
|
|
overlay.innerHTML = `
|
|
<div style="max-width: 600px; padding: 40px; text-align: center;">
|
|
<div class="spinner-border text-primary mb-4" role="status" style="width: 4rem; height: 4rem;"><span class="visually-hidden">Loading...</span></div>
|
|
<h2 class="mb-4">${instructions.title}</h2>
|
|
<div class="alert alert-info text-start" role="alert">
|
|
<ol class="mb-0" style="padding-left: 20px;">
|
|
<li class="mb-2"><strong>${instructions.step1}</strong></li>
|
|
<li class="mb-2">${instructions.step2}</li>
|
|
<li class="mb-2">${instructions.step3}</li>
|
|
<li class="mb-2">${instructions.step4}</li>
|
|
</ol>
|
|
</div>
|
|
<div class="alert alert-warning text-start" role="alert"><strong>Important:</strong> ${instructions.warning}</div>
|
|
<div class="mt-4">
|
|
<p class="text-muted">${lang === 'fr' ? 'Reconnexion à' : 'Reconnecting to'}: <strong class="text-white">${response.ssid}</strong></p>
|
|
<p class="text-muted">${lang === 'fr' ? 'Nom du capteur' : 'Sensor name'}: <strong class="text-white">${response.deviceName}</strong></p>
|
|
</div>
|
|
<div class="mt-4"><small class="text-muted">${lang === 'fr' ? 'Cette fenêtre va se fermer automatiquement...' : 'This window will close automatically...'}</small></div>
|
|
</div>`;
|
|
document.body.appendChild(overlay);
|
|
setTimeout(() => { const o = document.getElementById('connection-status-overlay'); if (o) o.remove(); }, 30000);
|
|
}
|
|
|
|
function wifi_forget(){
|
|
if (!confirm('Oublier le réseau WiFi actuel et passer en mode hotspot ?')) return;
|
|
$.ajax({
|
|
url: 'launcher.php?type=wifi_forget',
|
|
dataType: 'json',
|
|
method: 'GET',
|
|
success: function(response) {
|
|
console.log(response);
|
|
showForgetStatus(response);
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('AJAX request failed:', status, error);
|
|
alert('Error: Could not forget WiFi network');
|
|
}
|
|
});
|
|
}
|
|
|
|
function showForgetStatus(response) {
|
|
const lang = localStorage.getItem('language') || 'fr';
|
|
const instructions = response.instructions[lang] || response.instructions['fr'];
|
|
|
|
const overlay = document.createElement('div');
|
|
overlay.id = 'connection-status-overlay';
|
|
overlay.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.9);z-index:9999;display:flex;align-items:center;justify-content:center;color:white;';
|
|
overlay.innerHTML = `
|
|
<div style="max-width: 600px; padding: 40px; text-align: center;">
|
|
<div class="spinner-border text-warning mb-4" role="status" style="width: 4rem; height: 4rem;"><span class="visually-hidden">Loading...</span></div>
|
|
<h2 class="mb-4">${instructions.title}</h2>
|
|
<div class="alert alert-info text-start" role="alert">
|
|
<ol class="mb-0" style="padding-left: 20px;">
|
|
<li class="mb-2"><strong>${instructions.step1}</strong></li>
|
|
<li class="mb-2">${instructions.step2}</li>
|
|
<li class="mb-2">${instructions.step3}</li>
|
|
<li class="mb-2">${instructions.step4}</li>
|
|
</ol>
|
|
</div>
|
|
<div class="alert alert-warning text-start" role="alert"><strong>Important:</strong> ${instructions.warning}</div>
|
|
<div class="mt-4"><p class="text-muted">Hotspot: <strong class="text-white">${response.deviceName}</strong></p></div>
|
|
</div>`;
|
|
document.body.appendChild(overlay);
|
|
setTimeout(() => { const o = document.getElementById('connection-status-overlay'); if (o) o.remove(); }, 30000);
|
|
}
|
|
|
|
function wifi_scan(){
|
|
console.log("Scanning Wifi");
|
|
document.getElementById('wifi-scan-empty').innerHTML = '<div class="spinner-border spinner-border-sm text-primary" role="status"></div> Scan en cours...';
|
|
|
|
$.ajax({
|
|
url: 'launcher.php?type=wifi_scan',
|
|
dataType: 'json',
|
|
method: 'GET',
|
|
success: function(response) {
|
|
console.log(response);
|
|
const tableBody = document.getElementById("data-table-body_wifi_scan");
|
|
tableBody.innerHTML = "";
|
|
|
|
if (response.length === 0) {
|
|
document.getElementById('wifi-scan-empty').textContent = 'Aucun reseau WiFi trouve.';
|
|
document.getElementById('wifi-scan-empty').style.display = '';
|
|
document.getElementById('wifi-scan-table').style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
// Show cached scan notice if in hotspot mode
|
|
const isCached = response.length > 0 && response[0].cached;
|
|
const cacheNotice = document.getElementById('wifi-scan-cache-notice');
|
|
if (cacheNotice) cacheNotice.style.display = isCached ? '' : 'none';
|
|
|
|
document.getElementById('wifi-scan-empty').style.display = 'none';
|
|
document.getElementById('wifi-scan-table').style.display = '';
|
|
|
|
response.forEach(network => {
|
|
const row = document.createElement("tr");
|
|
|
|
const ssidCell = document.createElement("td");
|
|
ssidCell.textContent = network.SSID.length > 25 ? network.SSID.substring(0, 25) + '...' : network.SSID;
|
|
row.appendChild(ssidCell);
|
|
|
|
const signalCell = document.createElement("td");
|
|
signalCell.innerHTML = getSignalBadge(network.SIGNAL);
|
|
row.appendChild(signalCell);
|
|
|
|
const securityCell = document.createElement("td");
|
|
securityCell.textContent = network.SECURITY || '--';
|
|
securityCell.classList.add('text-muted');
|
|
row.appendChild(securityCell);
|
|
|
|
const buttonCell = document.createElement("td");
|
|
buttonCell.classList.add('text-end');
|
|
const button = document.createElement("button");
|
|
button.textContent = "Connecter";
|
|
button.classList.add("btn", "btn-primary", "btn-sm");
|
|
button.addEventListener("click", () => wifi_connect(network.SSID));
|
|
buttonCell.appendChild(button);
|
|
row.appendChild(buttonCell);
|
|
|
|
tableBody.appendChild(row);
|
|
});
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('AJAX request failed:', status, error);
|
|
document.getElementById('wifi-scan-empty').innerHTML = '<span class="text-danger">Erreur lors du scan</span>';
|
|
}
|
|
});
|
|
}
|
|
|
|
window.onload = function() {
|
|
$.ajax({
|
|
url: 'launcher.php?type=get_config_sqlite',
|
|
dataType: 'json',
|
|
method: 'GET',
|
|
success: function(data) {
|
|
console.log("Getting config (onload)");
|
|
const deviceName = data.deviceName;
|
|
|
|
function updateSidebarDeviceName(deviceName) {
|
|
const elements = document.querySelectorAll('.sideBar_sensorName');
|
|
if (elements.length > 0) {
|
|
elements.forEach((element) => {
|
|
element.innerText = deviceName;
|
|
});
|
|
}
|
|
}
|
|
|
|
if (deviceName) {
|
|
updateSidebarDeviceName(deviceName);
|
|
setTimeout(() => updateSidebarDeviceName(deviceName), 100);
|
|
setTimeout(() => updateSidebarDeviceName(deviceName), 500);
|
|
document.title = deviceName;
|
|
}
|
|
|
|
const WIFI_statusElement = document.getElementById("wifi-status");
|
|
|
|
if (data.WIFI_status === "connected") {
|
|
WIFI_statusElement.textContent = "Connected";
|
|
WIFI_statusElement.className = "badge text-bg-success";
|
|
document.getElementById('btn-forget-wifi').style.display = 'inline-block';
|
|
document.getElementById('card-connection-info').style.display = '';
|
|
document.getElementById('card-hotspot-info').style.display = 'none';
|
|
document.getElementById('card-wifi-scan').style.display = 'none';
|
|
get_internet();
|
|
} else if (data.WIFI_status === "hotspot") {
|
|
WIFI_statusElement.textContent = "Hotspot";
|
|
WIFI_statusElement.className = "badge text-bg-warning";
|
|
document.getElementById('btn-forget-wifi').style.display = 'none';
|
|
document.getElementById('card-connection-info').style.display = 'none';
|
|
document.getElementById('card-hotspot-info').style.display = '';
|
|
document.getElementById('card-wifi-scan').style.display = '';
|
|
wifi_scan();
|
|
} else {
|
|
WIFI_statusElement.textContent = "Unknown";
|
|
WIFI_statusElement.className = "badge text-bg-secondary";
|
|
document.getElementById('btn-forget-wifi').style.display = 'none';
|
|
document.getElementById('card-connection-info').style.display = 'none';
|
|
document.getElementById('card-hotspot-info').style.display = 'none';
|
|
document.getElementById('card-wifi-scan').style.display = '';
|
|
}
|
|
|
|
$.ajax({
|
|
url: 'launcher.php?type=RTC_time',
|
|
dataType: 'text',
|
|
method: 'GET',
|
|
success: function(response) {
|
|
const RTC_Element = document.getElementById("RTC_time");
|
|
RTC_Element.textContent = response;
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('AJAX request failed:', status, error);
|
|
}
|
|
});
|
|
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('AJAX request failed:', status, error);
|
|
}
|
|
});
|
|
}
|
|
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|