Files
nebuleair_pro_4g/html/wifi.html
PaulVua 8d74e3e678 Reduce fetch count: config partagee + suppression doublons internet
- topbar-logo.js expose la config via event 'nebuleair-config-ready'
- wifi.html ecoute l'event au lieu de re-fetcher get_config_sqlite
- Supprime le doublon load_ethernet_info (get_internet fait deja tout)
- Passe de ~9 requetes simultanees a ~5 au chargement

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 18:34:58 +01:00

606 lines
23 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-bar"></span> <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");
// Load topbar
fetch('topbar.html')
.then(r => r.text())
.then(data => { document.getElementById('topbar').innerHTML = data; })
.catch(e => console.error('Error loading topbar:', e));
// Load sidebar once, reuse for desktop + mobile
fetch('sidebar.html')
.then(r => r.text())
.then(data => {
document.getElementById('sidebar').innerHTML = data;
document.getElementById('sidebar_mobile').innerHTML = data;
})
.catch(e => console.error('Error loading sidebar:', e));
});
function load_ethernet_info() {
$.ajax({
url: 'launcher.php?type=internet',
dataType: 'json',
method: 'GET',
success: function(response) {
const eth = response.ethernet;
document.getElementById('info-eth-status').textContent = eth.connection || '-';
document.getElementById('info-eth-ip').textContent = eth.IP || '-';
}
});
}
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;
// WiFi info
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 || '-';
// Ethernet info
const ethStatus = eth.connection || '-';
document.getElementById('info-eth-status').textContent = ethStatus;
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");
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:");
// Close modal
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', // Changed to JSON
method: 'GET',
success: function(response) {
console.log(response);
// Show connection status message
showConnectionStatus(response);
},
error: function(xhr, status, error) {
console.error('AJAX request failed:', status, error);
alert('Error: Could not start connection process');
}
});
}
}
function showConnectionStatus(response) {
// Get user language (default to French)
const lang = localStorage.getItem('language') || 'fr';
const instructions = response.instructions[lang] || response.instructions['fr'];
// Create overlay with instructions
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);
// Auto-close after 30 seconds (gives time to read)
setTimeout(() => {
if (document.getElementById('connection-status-overlay')) {
document.getElementById('connection-status-overlay').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">
${lang === 'fr' ? 'Hotspot' : 'Hotspot'}:
<strong class="text-white">${response.deviceName}</strong>
</p>
</div>
</div>
`;
document.body.appendChild(overlay);
setTimeout(() => {
if (document.getElementById('connection-status-overlay')) {
document.getElementById('connection-status-overlay').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");
// SSID
const ssidCell = document.createElement("td");
const truncatedSSID = network.SSID.length > 25 ? network.SSID.substring(0, 25) + '...' : network.SSID;
ssidCell.textContent = truncatedSSID;
row.appendChild(ssidCell);
// Signal with badge
const signalCell = document.createElement("td");
signalCell.innerHTML = getSignalBadge(network.SIGNAL);
row.appendChild(signalCell);
// Security
const securityCell = document.createElement("td");
securityCell.textContent = network.SECURITY || '--';
securityCell.classList.add('text-muted');
row.appendChild(securityCell);
// Connect button
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>';
}
});
}
// Listen for config loaded by topbar-logo.js (avoids duplicate fetch)
document.addEventListener('nebuleair-config-ready', function(e) {
const data = e.detail;
console.log("Config received (wifi page):");
console.log(data);
// WiFi connection status — toggle cards
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";
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';
// Auto-load connection details (includes ethernet info)
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 = '';
// Auto-load cached scan results in hotspot mode
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 = '';
}
}
});
</script>
</body>
</html>