Squelette d'application web pour ESP32 avec implémentations de fonctions basiques telles que : -Authentification -Responsive design -Mise à jour OTA -Paramétrage
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

199 lines
7.8 KiB

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Paramètres - ESP32 Webapp</title>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<nav class="navbar">
<div class="nav-brand">🔔 ESP32 Webapp</div>
<div class="nav-menu">
<a href="/index.html">Tableau de bord</a>
<a href="/settings.html" class="active">Paramètres</a>
<a href="/update.html">Mise à jour</a>
<a href="/logout">Déconnexion</a>
</div>
</nav>
<div class="container">
<h1>Paramètres</h1>
<div class="card">
<h2>Configuration WiFi</h2>
<form id="wifiForm">
<div class="form-group">
<label for="wifi_ssid">SSID du réseau</label>
<input type="text" id="wifi_ssid" name="wifi_ssid">
</div>
<div class="form-group">
<label for="wifi_password">Mot de passe WiFi</label>
<input type="password" id="wifi_password" name="wifi_password" placeholder="Laisser vide pour ne pas changer">
</div>
<div class="form-group">
<label for="ap_password">Mot de passe du Point d'Accès</label>
<input type="password" id="ap_password" name="ap_password" placeholder="Laisser vide pour ne pas changer">
</div>
<button type="submit" class="btn btn-primary">Enregistrer WiFi</button>
</form>
</div>
<div class="card">
<h2>Configuration système</h2>
<form id="systemForm">
<div class="form-group">
<label for="hostname">Nom d'hôte</label>
<input type="text" id="hostname" name="hostname">
</div>
<div class="form-group">
<label for="session_timeout">Timeout de session (minutes)</label>
<input type="number" id="session_timeout" name="session_timeout" min="1" max="1440">
</div>
<button type="submit" class="btn btn-primary">Enregistrer système</button>
</form>
</div>
<div class="card">
<h2>Changer le mot de passe</h2>
<form id="passwordForm">
<div class="form-group">
<label for="current_password">Mot de passe actuel</label>
<input type="password" id="current_password" name="current_password" required>
</div>
<div class="form-group">
<label for="new_password">Nouveau mot de passe</label>
<input type="password" id="new_password" name="new_password" required>
</div>
<div class="form-group">
<label for="confirm_password">Confirmer le mot de passe</label>
<input type="password" id="confirm_password" name="confirm_password" required>
</div>
<button type="submit" class="btn btn-primary">Changer le mot de passe</button>
</form>
</div>
<div id="message" class="message"></div>
</div>
<script src="/js/api.js"></script>
<script src="/js/crypto-js.min.js"></script>
<script>
let config = {};
async function loadConfig() {
try {
config = await api.getConfig();
// WiFi
document.getElementById('wifi_ssid').value = config.wifi.ssid || '';
// Système
document.getElementById('hostname').value = config.system.hostname || '';
document.getElementById('session_timeout').value = config.system.session_timeout || 60;
} catch (error) {
showMessage('Erreur de chargement de la configuration', 'error');
}
}
function showMessage(text, type = 'info') {
const messageDiv = document.getElementById('message');
messageDiv.className = `message ${type}`;
messageDiv.textContent = text;
setTimeout(() => {
messageDiv.className = 'message';
messageDiv.textContent = '';
}, 5000);
}
document.getElementById('wifiForm').addEventListener('submit', async (e) => {
e.preventDefault();
config.wifi.ssid = document.getElementById('wifi_ssid').value;
const wifiPassword = document.getElementById('wifi_password').value;
if (wifiPassword) {
config.wifi.password = wifiPassword;
}
const apPassword = document.getElementById('ap_password').value;
if (apPassword) {
config.wifi.ap_password = apPassword;
}
try {
await api.setConfig(config);
showMessage('Configuration WiFi enregistrée. Redémarrage...', 'success');
} catch (error) {
showMessage('Erreur d\'enregistrement', 'error');
}
});
document.getElementById('systemForm').addEventListener('submit', async (e) => {
e.preventDefault();
config.system.hostname = document.getElementById('hostname').value;
config.system.session_timeout = parseInt(document.getElementById('session_timeout').value);
try {
await api.setConfig(config);
showMessage('Configuration système enregistrée. Redémarrage...', 'success');
} catch (error) {
showMessage('Erreur d\'enregistrement', 'error');
}
});
document.getElementById('passwordForm').addEventListener('submit', async (e) => {
e.preventDefault();
const currentPassword = document.getElementById('current_password').value;
const newPassword = document.getElementById('new_password').value;
const confirmPassword = document.getElementById('confirm_password').value;
if (newPassword !== confirmPassword) {
showMessage('Les mots de passe ne correspondent pas', 'error');
return;
}
if (newPassword.length < 4) {
showMessage('Le mot de passe doit contenir au moins 4 caractères', 'error');
return;
}
// Calculer le hash SHA-256 du nouveau mot de passe avec CryptoJS
const hashHex = CryptoJS.SHA256(newPassword).toString();
const passwordConfig = {
auth: {
old_password: currentPassword,
password_hash: hashHex
}
};
try {
await api.changePassword(passwordConfig);
showMessage('Mot de passe changé avec succès. Redémarrage...', 'success');
setTimeout(() => {
window.location.href = '/logout';
}, 2000);
} catch (error) {
if (error.message.includes('401')) {
showMessage('Mot de passe actuel incorrect', 'error');
} else {
showMessage('Erreur de changement de mot de passe: ' + error.message, 'error');
}
}
});
loadConfig();
</script>
</body>
</html>