Admin WiFi : scan réseaux, connexion, mots de passe mémorisés
- Module backend/wifi.py : scan nmcli, connexion, mots de passe persistés dans data/wifi_passwords.json
- Gère la locale FR (oui/non), déduplique les AP multiples, prend le meilleur signal
- Onglet WiFi dans le menu admin avec statut, scan, clavier virtuel AZERTY complet
- Réseaux enregistrés avec bouton connecter/oublier et affichage temporaire du mdp
- API: /api/wifi/status, /api/wifi/scan, /api/wifi/connect, /api/wifi/saved, /api/wifi/password/{ssid}
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1159,6 +1159,210 @@ async function regenererBoothPassword() {
|
||||
}
|
||||
}
|
||||
|
||||
// === WIFI ===
|
||||
|
||||
let _wifiMajActif = false;
|
||||
let _wifiSsidCible = null;
|
||||
|
||||
function _signalBars(signal, actif) {
|
||||
const seuils = [20, 40, 60, 80];
|
||||
return seuils.map(s =>
|
||||
`<div class="bar${signal >= s ? ' actif' : ''}"></div>`
|
||||
).join('');
|
||||
}
|
||||
|
||||
async function chargerWifi() {
|
||||
const statut = await apiGet('/api/wifi/status');
|
||||
const icon = document.getElementById('wifi-statut-icon');
|
||||
const ssid = document.getElementById('wifi-ssid');
|
||||
const detail = document.getElementById('wifi-detail');
|
||||
const bars = document.getElementById('wifi-signal-bars');
|
||||
|
||||
if (statut.connecte) {
|
||||
icon.textContent = '\u{1F4F6}';
|
||||
ssid.textContent = statut.ssid;
|
||||
detail.textContent = `IP : ${statut.ip || '—'}`;
|
||||
bars.innerHTML = _signalBars(statut.signal || 0, true);
|
||||
} else {
|
||||
icon.textContent = '\u{1F4F4}';
|
||||
ssid.textContent = 'Non connecté';
|
||||
detail.textContent = 'Aucun réseau WiFi';
|
||||
bars.innerHTML = _signalBars(0, false);
|
||||
}
|
||||
|
||||
await chargerWifiEnregistres();
|
||||
}
|
||||
|
||||
async function scannerWifi() {
|
||||
const liste = document.getElementById('wifi-liste-reseaux');
|
||||
const loading = document.getElementById('wifi-scan-loading');
|
||||
liste.innerHTML = '';
|
||||
loading.classList.remove('cache');
|
||||
|
||||
try {
|
||||
const reseaux = await apiGet('/api/wifi/scan');
|
||||
loading.classList.add('cache');
|
||||
if (reseaux.length === 0) {
|
||||
liste.innerHTML = '<p style="color:#888;padding:.5rem">Aucun réseau détecté</p>';
|
||||
return;
|
||||
}
|
||||
for (const r of reseaux) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'wifi-reseau' + (r.actif ? ' wifi-actif' : '');
|
||||
div.onclick = () => onWifiReseauClick(r);
|
||||
div.innerHTML = `
|
||||
<div class="wifi-reseau-icons">
|
||||
${r.securise ? '🔒' : '🔓'}
|
||||
</div>
|
||||
<div class="wifi-reseau-ssid">${_escHtml(r.ssid)}</div>
|
||||
<div class="wifi-reseau-meta">${r.securite || 'Ouvert'}</div>
|
||||
${r.actif ? '<span class="wifi-badge-connecte">Connecté</span>' : ''}
|
||||
${!r.actif && r.enregistre ? '<span class="wifi-badge-enregistre">Enregistré</span>' : ''}
|
||||
<div class="wifi-signal-bars">${_signalBars(r.signal)}</div>
|
||||
`;
|
||||
liste.appendChild(div);
|
||||
}
|
||||
} catch (e) {
|
||||
loading.classList.add('cache');
|
||||
liste.innerHTML = '<p style="color:#f44;padding:.5rem">Erreur scan WiFi</p>';
|
||||
}
|
||||
}
|
||||
|
||||
function onWifiReseauClick(reseau) {
|
||||
if (reseau.actif) return;
|
||||
if (reseau.enregistre) {
|
||||
connecterWifiDirect(reseau.ssid);
|
||||
} else if (!reseau.securise) {
|
||||
connecterWifiDirect(reseau.ssid);
|
||||
} else {
|
||||
afficherPopupWifiMdp(reseau.ssid);
|
||||
}
|
||||
}
|
||||
|
||||
async function connecterWifiDirect(ssid) {
|
||||
afficherStatut(`Connexion à ${ssid}...`, 'succes');
|
||||
const r = await apiPost('/api/wifi/connect', { ssid });
|
||||
if (r.succes) {
|
||||
afficherStatut(r.message, 'succes');
|
||||
await chargerWifi();
|
||||
await scannerWifi();
|
||||
} else {
|
||||
afficherStatut(r.message || 'Échec connexion', 'erreur');
|
||||
afficherPopupWifiMdp(ssid);
|
||||
}
|
||||
}
|
||||
|
||||
function afficherPopupWifiMdp(ssid) {
|
||||
_wifiSsidCible = ssid;
|
||||
document.getElementById('wifi-mdp-titre').textContent = `WiFi : ${ssid}`;
|
||||
document.getElementById('wifi-mdp-input').value = '';
|
||||
document.getElementById('wifi-mdp-erreur').classList.add('cache');
|
||||
document.getElementById('popup-wifi-mdp').classList.remove('cache');
|
||||
|
||||
apiGet(`/api/wifi/password/${encodeURIComponent(ssid)}`).then(data => {
|
||||
if (data.password) {
|
||||
document.getElementById('wifi-mdp-input').value = data.password;
|
||||
}
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
function fermerPopupWifi() {
|
||||
document.getElementById('popup-wifi-mdp').classList.add('cache');
|
||||
_wifiSsidCible = null;
|
||||
}
|
||||
|
||||
let _wifiMaj = false;
|
||||
function wifiTape(c) {
|
||||
const input = document.getElementById('wifi-mdp-input');
|
||||
if (_wifiMaj && c.length === 1 && c.match(/[a-z]/)) c = c.toUpperCase();
|
||||
input.value += c;
|
||||
if (_wifiMaj) { _wifiMaj = false; _wifiMajUI(); }
|
||||
}
|
||||
|
||||
function wifiEffacer() {
|
||||
const input = document.getElementById('wifi-mdp-input');
|
||||
input.value = input.value.slice(0, -1);
|
||||
}
|
||||
|
||||
function wifiToggleMaj() {
|
||||
_wifiMaj = !_wifiMaj;
|
||||
_wifiMajUI();
|
||||
}
|
||||
|
||||
function _wifiMajUI() {
|
||||
const btn = document.getElementById('wifi-btn-maj');
|
||||
btn.style.background = _wifiMaj ? 'var(--primaire)' : '';
|
||||
btn.style.color = _wifiMaj ? '#fff' : '';
|
||||
['wifi-kb-row1', 'wifi-kb-row2', 'wifi-kb-row3'].forEach(id => {
|
||||
document.getElementById(id).querySelectorAll('button').forEach(b => {
|
||||
const c = b.textContent;
|
||||
if (c.length === 1 && c.match(/[a-zA-Z]/)) {
|
||||
b.textContent = _wifiMaj ? c.toUpperCase() : c.toLowerCase();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function validerWifiMdp() {
|
||||
const mdp = document.getElementById('wifi-mdp-input').value;
|
||||
if (!mdp) return;
|
||||
const btn = document.getElementById('wifi-btn-connecter');
|
||||
btn.textContent = 'Connexion...';
|
||||
btn.disabled = true;
|
||||
const r = await apiPost('/api/wifi/connect', { ssid: _wifiSsidCible, password: mdp });
|
||||
btn.textContent = 'Connecter';
|
||||
btn.disabled = false;
|
||||
if (r.succes) {
|
||||
fermerPopupWifi();
|
||||
afficherStatut(r.message, 'succes');
|
||||
await chargerWifi();
|
||||
await scannerWifi();
|
||||
} else {
|
||||
const err = document.getElementById('wifi-mdp-erreur');
|
||||
err.textContent = r.message || 'Échec connexion';
|
||||
err.classList.remove('cache');
|
||||
setTimeout(() => err.classList.add('cache'), 4000);
|
||||
}
|
||||
}
|
||||
|
||||
async function chargerWifiEnregistres() {
|
||||
const liste = document.getElementById('wifi-liste-enregistres');
|
||||
const saved = await apiGet('/api/wifi/saved');
|
||||
liste.innerHTML = '';
|
||||
if (saved.length === 0) {
|
||||
liste.innerHTML = '<p style="color:#888;padding:.5rem;font-size:.85rem">Aucun réseau enregistré</p>';
|
||||
return;
|
||||
}
|
||||
for (const s of saved) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'wifi-enregistre-item';
|
||||
div.innerHTML = `
|
||||
<span class="wifi-reseau-ssid">${_escHtml(s.ssid)}</span>
|
||||
${s.mdp_connu ? `<span class="wifi-enregistre-mdp" onclick="afficherMdpWifi('${_escAttr(s.ssid)}', this)" title="Voir le mot de passe">👁 mdp</span>` : ''}
|
||||
<button class="btn-secondaire btn-petit" onclick="connecterWifiDirect('${_escAttr(s.ssid)}')">Connecter</button>
|
||||
<button class="btn-danger btn-petit" onclick="oublierWifi('${_escAttr(s.ssid)}')">Oublier</button>
|
||||
`;
|
||||
liste.appendChild(div);
|
||||
}
|
||||
}
|
||||
|
||||
async function afficherMdpWifi(ssid, el) {
|
||||
const data = await apiGet(`/api/wifi/password/${encodeURIComponent(ssid)}`);
|
||||
if (data.password) {
|
||||
el.textContent = data.password;
|
||||
setTimeout(() => { el.innerHTML = '👁 mdp'; }, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
async function oublierWifi(ssid) {
|
||||
await fetch(`/api/wifi/saved/${encodeURIComponent(ssid)}`, { method: 'DELETE' });
|
||||
afficherStatut(`${ssid} oublié`, 'succes');
|
||||
await chargerWifiEnregistres();
|
||||
}
|
||||
|
||||
function _escHtml(s) { const d = document.createElement('div'); d.textContent = s; return d.innerHTML; }
|
||||
function _escAttr(s) { return s.replace(/'/g, "\\'").replace(/"/g, '"'); }
|
||||
|
||||
async function chargerDiagCamera() {
|
||||
const el = document.getElementById('diag-camera-contenu');
|
||||
el.textContent = 'Test en cours...';
|
||||
|
||||
Reference in New Issue
Block a user