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.
 
 

487 lines
21 KiB

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Contrôleur Solaire - Configuration</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 50px auto;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
.container {
background: white;
padding: 40px;
border-radius: 10px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
}
h1 {
color: #333;
text-align: center;
margin-bottom: 30px;
}
h2 {
color: #667eea;
border-bottom: 2px solid #667eea;
padding-bottom: 10px;
margin-top: 30px;
}
.nav-links {
text-align: center;
margin-top: 30px;
}
.nav-links a {
display: inline-block;
padding: 10px 20px;
background: #95a5a6;
color: white;
text-decoration: none;
border-radius: 5px;
margin: 5px;
transition: background 0.3s;
}
.nav-links a:hover {
background: #7f8c8d;
}
.form-section {
background: #f9f9f9;
padding: 20px;
border-radius: 5px;
margin-bottom: 20px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
color: #555;
font-weight: bold;
}
input[type="text"],
input[type="password"],
input[type="number"] {
width: 100%;
padding: 10px;
border: 2px solid #ddd;
border-radius: 5px;
font-size: 16px;
box-sizing: border-box;
}
input[type="text"]:focus,
input[type="password"]:focus,
input[type="number"]:focus {
outline: none;
border-color: #667eea;
}
.password-hint {
font-size: 12px;
color: #777;
margin-top: 5px;
}
button {
padding: 12px 30px;
background: #667eea;
color: white;
border: none;
border-radius: 5px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
transition: background 0.3s;
margin-right: 10px;
}
button:hover {
background: #764ba2;
}
button:disabled {
background: #ccc;
cursor: not-allowed;
}
button.secondary {
background: #95a5a6;
}
button.secondary:hover {
background: #7f8c8d;
}
.message {
padding: 15px;
border-radius: 5px;
margin-bottom: 20px;
display: none;
}
.message.success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.message.error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.loading {
text-align: center;
color: #667eea;
font-style: italic;
}
</style>
</head>
<body>
<div class="container">
<h1> Configuration</h1>
<div id="message" class="message"></div>
<div id="loading" class="loading" style="display:none;">Chargement...</div>
<form id="settingsForm">
<!-- Section Authentification -->
<h2>🔐 Authentification</h2>
<div class="form-section">
<div class="form-group">
<label for="username">Nom d'utilisateur:</label>
<input type="text" id="username" name="username" required>
</div>
<div class="form-group">
<label for="current_password">Mot de passe actuel:</label>
<input type="password" id="current_password" name="current_password" placeholder="Laisser vide pour ne pas changer">
<div class="password-hint">Requis uniquement si vous changez le mot de passe</div>
</div>
<div class="form-group">
<label for="new_password">Nouveau mot de passe:</label>
<input type="password" id="new_password" name="new_password" placeholder="Laisser vide pour garder l'actuel">
<div class="password-hint">Minimum 8 caractères recommandé</div>
</div>
<div class="form-group">
<label for="confirm_password">Confirmer le nouveau mot de passe:</label>
<input type="password" id="confirm_password" name="confirm_password" placeholder="Confirmer le nouveau mot de passe">
</div>
</div>
<!-- Section Système -->
<h2>🌐 Configuration Système</h2>
<div class="form-section">
<div class="form-group">
<label for="hostname">Nom d'hôte :</label>
<input type="text" id="hostname" name="hostname" placeholder="ESP12-OTA">
<div class="password-hint">Nom de l'appareil sur le réseau</div>
</div>
<div class="form-group">
<label for="session_timeout">Durée de session (minutes):</label>
<input type="number" id="session_timeout" name="session_timeout" min="5" max="1440" value="60">
<div class="password-hint">Durée avant déconnexion automatique (5-1440 min)</div>
</div>
<div class="form-group">
<label for="wifi_ssid">Nom du réseau (SSID):</label>
<input type="text" id="wifi_ssid" name="wifi_ssid" placeholder="Nom du réseau WiFi">
<div class="password-hint">SSID du réseau WiFi auquel se connecter</div>
</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 class="password-hint"> Attention: Un redémarrage sera nécessaire pour appliquer les changements WiFi</div>
</div>
<div class="form-group">
<label for="ap_password">Mot de passe mode AP (secours):</label>
<input type="text" id="ap_password" name="ap_password" placeholder="123456">
<div class="password-hint">Mot de passe pour se connecter à l'ESP si impossible de rejoindre le WiFi (minimum 8 caractères)</div>
</div>
</div>
<!-- Section Paramètres routeur -->
<h2> Configuration routeur</h2>
<div class="form-section">
<div class="form-group">
<label for="heater_max_power">Puissance chauffe-eau (Watts):</label>
<input type="number" id="heater_max_power" name="heater_max_power" min="500" max="5000" value="2400">
<div class="password-hint">Puissance maximale du chauffe-eau</div>
</div>
<div class="form-group">
<label for="min_water_temp">Température eau minimale (°C):</label>
<input type="number" id="min_water_temp" name="min_water_temp" min="20" max="80" step="0.1" value="40.0">
<div class="password-hint">Température minimale de l'eau du chauffe-eau (mode NUIT)</div>
</div>
<div class="form-group">
<label for="max_water_temp">Température eau maximale (°C):</label>
<input type="number" id="max_water_temp" name="max_water_temp" min="20" max="80" step="0.1" value="60.0">
<div class="password-hint">Température cible maximale de l'eau (mode JOUR)</div>
</div>
<div class="form-group">
<label for="coeff_jour">Coefficient mode JOUR:</label>
<input type="number" id="coeff_jour" name="coeff_jour" min="1" max="1000" step="1" value="350">
<div class="password-hint">Coefficient pour le calcul de puissance en mode JOUR</div>
</div>
<div class="form-group">
<label for="target_max_water_temp_hour">Heure cible température max (0-23):</label>
<input type="number" id="target_max_water_temp_hour" name="target_max_water_temp_hour" min="0" max="23" value="17">
<div class="password-hint">Heure à laquelle l'eau doit atteindre la température maximale (mode JOUR)</div>
</div>
<div class="form-group">
<label for="latitude">Latitude:</label>
<input type="number" id="latitude" name="latitude" min="-90" max="90" step="0.00001" value="49.01023">
<div class="password-hint">Latitude pour calcul lever/coucher du soleil</div>
</div>
<div class="form-group">
<label for="longitude">Longitude:</label>
<input type="number" id="longitude" name="longitude" min="-180" max="180" step="0.00001" value="2.03552">
<div class="password-hint">Longitude pour calcul lever/coucher du soleil</div>
</div>
<div class="form-group">
<label for="night_start_hour">Heure début nuit (0-23):</label>
<input type="number" id="night_start_hour" name="night_start_hour" min="0" max="23" value="0">
<div class="password-hint">Heure de début de la période nuit pour le mode NUIT</div>
</div>
<div class="form-group">
<label for="night_end_hour">Heure fin nuit (0-23):</label>
<input type="number" id="night_end_hour" name="night_end_hour" min="0" max="23" value="4">
<div class="password-hint">Heure de fin de la période nuit pour le mode NUIT</div>
</div>
</div>
<!-- Section Passerelle Enphase -->
<h2> Passerelle Enphase</h2>
<div class="form-section">
<div class="form-group">
<label for="enphase_ip">Adresse IP de la passerelle:</label>
<input type="text" id="enphase_ip" name="enphase_ip" placeholder="192.168.0.201">
<div class="password-hint">Adresse IP locale de votre passerelle Enphase Envoy</div>
</div>
<div class="form-group">
<label for="enphase_token">Token d'authentification:</label>
<input type="text" id="enphase_token" name="enphase_token" placeholder="eyJraWQiOi...">
<div class="password-hint">Token JWT Bearer pour l'API Enphase (obtenu depuis entrez.enphaseenergy.com)</div>
</div>
<div class="form-group">
<label for="update_interval">Intervalle de mise à jour (secondes):</label>
<input type="number" id="update_interval" name="update_interval" min="2" max="60" value="5">
<div class="password-hint">Fréquence de récupération des données (2-60 sec)</div>
</div>
</div>
<!-- Boutons d'action -->
<div style="margin-top: 30px;">
<button type="submit">💾 Enregistrer les modifications</button>
<button type="button" class="secondary" onclick="loadSettings()">🔄 Recharger</button>
</div>
</form>
<div class="nav-links">
<a href="/">🏠 Accueil</a>
<a href="/update.html">📦 Mise à jour OTA</a>
</div>
</div>
<script>
// Charger les paramètres au démarrage
window.addEventListener('DOMContentLoaded', loadSettings);
function showMessage(text, type) {
const messageDiv = document.getElementById('message');
messageDiv.textContent = text;
messageDiv.className = 'message ' + type;
messageDiv.style.display = 'block';
setTimeout(() => {
messageDiv.style.display = 'none';
}, 5000);
}
function loadSettings() {
const loading = document.getElementById('loading');
loading.style.display = 'block';
fetch('/api/settings')
.then(response => response.json())
.then(data => {
loading.style.display = 'none';
document.getElementById('username').value = data.auth.username || 'admin';
// Paramètres WiFi
if (data.wifi) {
document.getElementById('wifi_ssid').value = data.wifi.ssid || '';
document.getElementById('ap_password').value = data.wifi.ap_password || '123456';
// Ne pas charger le mot de passe WiFi pour des raisons de sécurité
document.getElementById('wifi_password').value = '';
}
document.getElementById('hostname').value = data.system.hostname || 'ESP12-OTA';
document.getElementById('session_timeout').value = data.system.session_timeout || 60;
document.getElementById('heater_max_power').value = data.system.heater_max_power || 2400;
document.getElementById('min_water_temp').value = data.system.min_water_temp || 40.0;
document.getElementById('max_water_temp').value = data.system.max_water_temp || 60.0;
document.getElementById('coeff_jour').value = data.system.coeff_jour || 350;
document.getElementById('target_max_water_temp_hour').value = data.system.target_max_water_temp_hour || 17;
document.getElementById('latitude').value = data.system.latitude || 49.01023;
document.getElementById('longitude').value = data.system.longitude || 2.03552;
document.getElementById('night_start_hour').value = data.system.night_start_hour || 0;
document.getElementById('night_end_hour').value = data.system.night_end_hour || 4;
// Paramètres Enphase
if (data.enphase) {
document.getElementById('enphase_ip').value = data.enphase.gateway_ip || '';
document.getElementById('enphase_token').value = data.enphase.token || '';
document.getElementById('update_interval').value = data.enphase.update_interval || 5;
}
// Réinitialiser les champs de mot de passe
document.getElementById('current_password').value = '';
document.getElementById('new_password').value = '';
document.getElementById('confirm_password').value = '';
})
.catch(error => {
loading.style.display = 'none';
showMessage('Erreur lors du chargement des paramètres', 'error');
console.error('Erreur:', error);
});
}
document.getElementById('settingsForm').addEventListener('submit', function(e) {
e.preventDefault();
const newPassword = document.getElementById('new_password').value;
const confirmPassword = document.getElementById('confirm_password').value;
const currentPassword = document.getElementById('current_password').value;
// Validation du mot de passe
if (newPassword && newPassword !== confirmPassword) {
showMessage('Les mots de passe ne correspondent pas', 'error');
return;
}
if (newPassword && !currentPassword) {
showMessage('Le mot de passe actuel est requis pour changer le mot de passe', 'error');
return;
}
if (newPassword && newPassword.length < 4) {
showMessage('Le nouveau mot de passe doit contenir au moins 4 caractères', 'error');
return;
}
// Préparer les données
const settings = {
auth: {
username: document.getElementById('username').value,
current_password: currentPassword,
new_password: newPassword
},
wifi: {
ssid: document.getElementById('wifi_ssid').value,
password: document.getElementById('wifi_password').value,
ap_password: document.getElementById('ap_password').value
},
system: {
hostname: document.getElementById('hostname').value,
session_timeout: parseInt(document.getElementById('session_timeout').value),
heater_max_power: parseInt(document.getElementById('heater_max_power').value),
min_water_temp: parseFloat(document.getElementById('min_water_temp').value),
max_water_temp: parseFloat(document.getElementById('max_water_temp').value),
coeff_jour: parseFloat(document.getElementById('coeff_jour').value),
target_max_water_temp_hour: parseInt(document.getElementById('target_max_water_temp_hour').value),
latitude: parseFloat(document.getElementById('latitude').value),
longitude: parseFloat(document.getElementById('longitude').value),
night_start_hour: parseInt(document.getElementById('night_start_hour').value),
night_end_hour: parseInt(document.getElementById('night_end_hour').value)
},
enphase: {
gateway_ip: document.getElementById('enphase_ip').value,
token: document.getElementById('enphase_token').value,
update_interval: parseInt(document.getElementById('update_interval').value)
}
};
// Envoyer les données
const loading = document.getElementById('loading');
loading.style.display = 'block';
fetch('/api/settings', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(settings)
})
.then(response => {
loading.style.display = 'none';
if (response.ok) {
return response.json();
} else {
throw new Error('Erreur lors de la sauvegarde');
}
})
.then(data => {
const wifiChanged = document.getElementById('wifi_ssid').value || document.getElementById('wifi_password').value;
if (wifiChanged) {
showMessage(data.message + ' - L\'ESP va redémarrer pour appliquer les changements WiFi.', 'success');
setTimeout(() => {
showMessage('Redémarrage en cours... Reconnexion au nouveau réseau nécessaire.', 'error');
}, 3000);
} else {
showMessage(data.message || 'Paramètres sauvegardés avec succès!', 'success');
}
// Si le mot de passe a changé, rediriger vers login après 2 secondes
if (newPassword) {
setTimeout(() => {
window.location.href = '/logout';
}, 2000);
} else {
// Recharger les paramètres
setTimeout(() => {
loadSettings();
}, 1000);
}
})
.catch(error => {
loading.style.display = 'none';
showMessage('Erreur lors de la sauvegarde des paramètres', 'error');
console.error('Erreur:', error);
});
});
</script>
</body>
</html>