(29-05-2025, 07:49 PM)grostoto a écrit : bonje test
doit y avoir un cheveux dans le potage..
ligne 534 je met ceci:
Code :<!-- <span class="frame-label" id="label1">Interface 1</span> -->
certes cela me supprime l'étiquette.. mais cela me supprime aussi l'affichage du 2d routeur.. (écran splitté de droite noir)
dès que je décommente, cela réapparait.
oui un oubli ....il faut aussi commenter cette ligne
// label.textContent = config[`name${i}`] || `Interface ${i}`;
Code :
// ESP32 Dashboard avec mode AP pour configuration initiale
#include <WiFi.h>
#include <WebServer.h>
#include <EEPROM.h>
#include <ArduinoJson.h>
// Structure pour stocker la config en EEPROM
struct Config {
char magic[4]; // "RMS" pour vérifier si config valide
char ssid[32];
char password[64];
char dashUser[32]; // Nom d'utilisateur pour le dashboard
char dashPass[32]; // Mot de passe pour le dashboard
char ip1[16];
char ip2[16];
char ip3[16];
char ip4[16];
char name1[32];
char name2[32];
char name3[32];
char name4[32];
};
Config config;
WebServer server(80);
bool isAPMode = false;
// Page de configuration en mode AP
const char config_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Configuration Dashboard RMS</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background: #1a1a2e;
color: white;
}
.container {
max-width: 600px;
margin: 0 auto;
background: rgba(255,255,255,0.1);
padding: 30px;
border-radius: 10px;
}
h1 {
text-align: center;
color: #4CAF50;
}
.section {
background: rgba(0,0,0,0.3);
padding: 20px;
margin: 20px 0;
border-radius: 5px;
}
h2 {
color: #2196F3;
margin-top: 0;
}
label {
display: block;
margin: 10px 0 5px;
}
input, select {
width: 100%;
padding: 10px;
border: 1px solid #555;
border-radius: 3px;
background: #333;
color: white;
box-sizing: border-box;
}
.ip-group {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 10px;
margin: 10px 0;
}
button {
background: #4CAF50;
color: white;
padding: 12px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
width: 100%;
margin-top: 20px;
}
button:hover {
background: #45a049;
}
.scan-btn {
background: #2196F3;
margin: 10px 0;
}
#scanResults {
max-height: 200px;
overflow-y: auto;
background: rgba(0,0,0,0.5);
padding: 10px;
border-radius: 3px;
margin: 10px 0;
}
.network-item {
padding: 5px;
cursor: pointer;
border-bottom: 1px solid #444;
}
.network-item:hover {
background: rgba(255,255,255,0.1);
}
.loading {
text-align: center;
color: #4CAF50;
}
.info {
background: #ff9800;
color: black;
padding: 10px;
border-radius: 5px;
margin: 10px 0;
text-align: center;
}
</style>
</head>
<body>
<div class="container">
<h1>Configuration Dashboard RMS</h1>
<div class="info" id="networkInfo">
<!-- L'info sera remplie dynamiquement -->
</div>
<div class="section">
<h2>1. Configuration WiFi</h2>
<div id="currentWifi" style="background: #4CAF50; color: white; padding: 10px; border-radius: 3px; margin-bottom: 10px; display: none;">
? Connecté à : <strong id="wifiName">---</strong>
</div>
<button class="scan-btn" onclick="scanNetworks()">? Scanner les réseaux</button>
<div id="scanResults"></div>
<label>SSID:</label>
<input type="text" id="ssid" placeholder="Nom du réseau WiFi">
<label>Mot de passe:</label>
<input type="password" id="password" placeholder="Mot de passe WiFi">
</div>
<div class="section">
<h2>2. Sécurité du Dashboard</h2>
<label>Nom d'utilisateur:</label>
<input type="text" id="dashUser" placeholder="admin">
<label>Mot de passe:</label>
<input type="password" id="dashPass" placeholder="Mot de passe dashboard">
<p style="color: #aaa; font-size: 12px;">Laissez vide pour désactiver l'authentification</p>
</div>
<div class="section">
<h2>3. Configuration des interfaces RMS</h2>
<p style="color: #aaa;">Configurez entre 2 et 4 interfaces</p>
<div class="ip-group">
<input type="text" id="ip1" placeholder="IP Interface 1 (ex: 192.168.1.100)">
<input type="text" id="name1" placeholder="Nom 1">
</div>
<div class="ip-group">
<input type="text" id="ip2" placeholder="IP Interface 2 (ex: 192.168.1.101)">
<input type="text" id="name2" placeholder="Nom 2">
</div>
<div class="ip-group">
<input type="text" id="ip3" placeholder="IP Interface 3 (optionnel)">
<input type="text" id="name3" placeholder="Nom 3">
</div>
<div class="ip-group">
<input type="text" id="ip4" placeholder="IP Interface 4 (optionnel)">
<input type="text" id="name4" placeholder="Nom 4">
</div>
</div>
<button onclick="saveConfig()">? Sauvegarder et redémarrer</button>
<button style="background: #666; margin-top: 10px;" onclick="window.location.href='/'">
↩️ Retour au Dashboard
</button>
<div id="message"></div>
</div>
<script>
// Charger la config existante au démarrage
window.onload = function() {
// Afficher l'info réseau
fetch('/networkinfo')
.then(response => response.json())
.then(info => {
const networkInfo = document.getElementById('networkInfo');
if (info.isAP) {
networkInfo.innerHTML = 'Mode Configuration - Connectez-vous au WiFi pour continuer';
networkInfo.style.background = '#ff9800';
} else {
networkInfo.innerHTML = `IP réseau : ${info.ip}`;
networkInfo.style.background = '#4CAF50';
}
});
fetch('/getconfig')
.then(response => response.json())
.then(data => {
// Pré-remplir les IPs et noms
if (data.ip1) document.getElementById('ip1').value = data.ip1;
if (data.ip2) document.getElementById('ip2').value = data.ip2;
if (data.ip3) document.getElementById('ip3').value = data.ip3;
if (data.ip4) document.getElementById('ip4').value = data.ip4;
if (data.name1) document.getElementById('name1').value = data.name1;
if (data.name2) document.getElementById('name2').value = data.name2;
if (data.name3) document.getElementById('name3').value = data.name3;
if (data.name4) document.getElementById('name4').value = data.name4;
// AJOUT : Afficher le WiFi actuel si connecté
if (data.ssid && window.location.hostname !== '192.168.4.1') {
document.getElementById('currentWifi').style.display = 'block';
document.getElementById('wifiName').textContent = data.ssid;
}
})
.catch(err => {
console.log('Pas de config existante');
});
};
function scanNetworks() {
document.getElementById('scanResults').innerHTML = '<div class="loading">Scan en cours...</div>';
fetch('/scan')
.then(response => response.json())
.then(data => {
let html = '';
data.networks.forEach(network => {
html += `<div class="network-item" onclick="selectNetwork('${network.ssid}')">
? ${network.ssid} (${network.rssi} dBm)
</div>`;
});
document.getElementById('scanResults').innerHTML = html || 'Aucun réseau trouvé';
});
}
function selectNetwork(ssid) {
document.getElementById('ssid').value = ssid;
}
function saveConfig() {
const config = {
ssid: document.getElementById('ssid').value,
password: document.getElementById('password').value,
dashUser: document.getElementById('dashUser').value,
dashPass: document.getElementById('dashPass').value,
ip1: document.getElementById('ip1').value,
ip2: document.getElementById('ip2').value,
ip3: document.getElementById('ip3').value,
ip4: document.getElementById('ip4').value,
name1: document.getElementById('name1').value || 'Interface 1',
name2: document.getElementById('name2').value || 'Interface 2',
name3: document.getElementById('name3').value || 'Interface 3',
name4: document.getElementById('name4').value || 'Interface 4'
};
// Validation
if (!config.ssid || !config.password) {
alert('Veuillez remplir les informations WiFi');
return;
}
if (!config.ip1 || !config.ip2) {
alert('Veuillez configurer au moins 2 interfaces');
return;
}
document.getElementById('message').innerHTML = '<div class="loading">Sauvegarde en cours...</div>';
fetch('/save', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(config)
})
.then(response => response.text())
.then(data => {
document.getElementById('message').innerHTML =
'<div class="info">Configuration sauvegardée! Redémarrage dans 5 secondes...</div>';
setTimeout(() => {
document.getElementById('message').innerHTML +=
'<div class="info">Connectez-vous au WiFi configuré pour accéder au dashboard</div>';
}, 2000);
});
}
</script>
</body>
</html>
)rawliteral";
// Page de login
const char login_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Dashboard RMS</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background: #1a1a2e;
color: white;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.login-box {
background: rgba(255,255,255,0.1);
padding: 40px;
border-radius: 10px;
box-shadow: 0 0 20px rgba(0,0,0,0.5);
width: 300px;
}
h2 {
text-align: center;
color: #4CAF50;
margin-bottom: 30px;
}
input {
width: 100%;
padding: 12px;
margin: 10px 0;
border: 1px solid #555;
border-radius: 5px;
background: #333;
color: white;
box-sizing: border-box;
}
button {
width: 100%;
padding: 12px;
margin-top: 20px;
background: #4CAF50;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background: #45a049;
}
.error {
color: #ff4444;
text-align: center;
margin-top: 10px;
}
</style>
</head>
<body>
<div class="login-box">
<h2>? Dashboard RMS</h2>
<form action="/login" method="POST">
<input type="text" name="user" placeholder="Nom d'utilisateur" required>
<input type="password" name="pass" placeholder="Mot de passe" required>
<button type="submit">Se connecter</button>
</form>
<div id="error" class="error"></div>
</div>
<script>
if (window.location.search.includes('error=1')) {
document.getElementById('error').textContent = 'Identifiants incorrects';
}
</script>
</body>
</html>
)rawliteral";
// Page dashboard modifiée avec bouton plein écran
const char dashboard_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard RMS</title>
<style>
body {
margin: 0;
padding: 0;
background: #222;
font-family: Arial, sans-serif;
height: 100vh;
overflow: hidden;
}
#dashboard {
display: grid;
height: 100vh;
gap: 2px;
transition: all 0.3s ease;
}
#dashboard.fullscreen {
display: block !important;
}
.layout-2 {
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr;
}
.layout-3 {
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
}
.layout-3 .frame-container:first-child {
grid-row: span 2;
}
.layout-4 {
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
}
.frame-container {
position: relative;
overflow: hidden;
background: white;
display: none;
}
.frame-container.active {
display: block;
}
.frame-container.fullscreen-active {
display: block !important;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 50;
}
.frame-wrapper {
width: 100%;
height: 100%;
transform-origin: top left;
transition: transform 0.3s ease;
}
iframe {
width: 100%;
height: 100%;
border: none;
background: white;
}
.frame-header {
position: absolute;
top: 5px;
left: 5px;
display: flex;
align-items: center;
gap: 10px;
z-index: 10;
}
.frame-label {
background: rgba(0,0,0,0.8);
color: white;
padding: 5px 10px;
font-size: 12px;
border-radius: 3px;
pointer-events: none;
}
.fullscreen-btn {
background: rgba(0,0,0,0.8);
color: white;
border: none;
padding: 5px 8px;
font-size: 12px;
border-radius: 3px;
cursor: pointer;
transition: background 0.2s;
}
.fullscreen-btn:hover {
background: rgba(0,0,0,0.9);
}
.fullscreen-btn.exit {
background: rgba(220,53,69,0.9);
}
.fullscreen-btn.exit:hover {
background: rgba(220,53,69,1);
}
/* Contrôles de zoom */
.zoom-controls {
position: absolute;
top: 5px;
right: 5px;
background: rgba(0,0,0,0.8);
padding: 5px;
border-radius: 3px;
z-index: 10;
display: flex;
gap: 5px;
}
.zoom-btn {
width: 25px;
height: 25px;
border: none;
background: #444;
color: white;
cursor: pointer;
border-radius: 3px;
font-size: 16px;
display: flex;
align-items: center;
justify-content: center;
}
.zoom-btn:hover {
background: #666;
}
.zoom-value {
color: white;
font-size: 12px;
min-width: 45px;
text-align: center;
display: flex;
align-items: center;
}
.btn-config {
position: fixed;
bottom: 10px;
right: 10px;
background: #2196F3;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
z-index: 100;
}
.btn-config:hover {
background: #1976D2;
}
.hidden {
display: none !important;
}
</style>
</head>
<body>
<div id="dashboard">
<div class="frame-container" id="frame1-container">
<div class="frame-header">
<span class="frame-label" id="label1">Interface 1</span>
<button class="fullscreen-btn" onclick="toggleFullscreen(1)" id="fullscreen-btn-1">⛶</button>
</div>
<div class="zoom-controls">
<button class="zoom-btn" onclick="zoom(1, -0.1)">−</button>
<span class="zoom-value" id="zoom1">100%</span>
<button class="zoom-btn" onclick="zoom(1, 0.1)">+</button>
</div>
<div class="frame-wrapper" id="wrapper1">
<iframe id="frame1"></iframe>
</div>
</div>
<div class="frame-container" id="frame2-container">
<div class="frame-header">
<span class="frame-label" id="label2">Interface 2</span>
<button class="fullscreen-btn" onclick="toggleFullscreen(2)" id="fullscreen-btn-2">⛶</button>
</div>
<div class="zoom-controls">
<button class="zoom-btn" onclick="zoom(2, -0.1)">−</button>
<span class="zoom-value" id="zoom2">100%</span>
<button class="zoom-btn" onclick="zoom(2, 0.1)">+</button>
</div>
<div class="frame-wrapper" id="wrapper2">
<iframe id="frame2"></iframe>
</div>
</div>
<div class="frame-container" id="frame3-container">
<div class="frame-header">
<span class="frame-label" id="label3">Interface 3</span>
<button class="fullscreen-btn" onclick="toggleFullscreen(3)" id="fullscreen-btn-3">⛶</button>
</div>
<div class="zoom-controls">
<button class="zoom-btn" onclick="zoom(3, -0.1)">−</button>
<span class="zoom-value" id="zoom3">100%</span>
<button class="zoom-btn" onclick="zoom(3, 0.1)">+</button>
</div>
<div class="frame-wrapper" id="wrapper3">
<iframe id="frame3"></iframe>
</div>
</div>
<div class="frame-container" id="frame4-container">
<div class="frame-header">
<span class="frame-label" id="label4">Interface 4</span>
<button class="fullscreen-btn" onclick="toggleFullscreen(4)" id="fullscreen-btn-4">⛶</button>
</div>
<div class="zoom-controls">
<button class="zoom-btn" onclick="zoom(4, -0.1)">−</button>
<span class="zoom-value" id="zoom4">100%</span>
<button class="zoom-btn" onclick="zoom(4, 0.1)">+</button>
</div>
<div class="frame-wrapper" id="wrapper4">
<iframe id="frame4"></iframe>
</div>
</div>
</div>
<button class="btn-config" onclick="window.location.href='/config'">
⚙️ Configuration
</button>
<script>
// Stocker les niveaux de zoom et l'état plein écran
const zoomLevels = {1: 1, 2: 1, 3: 1, 4: 1};
let currentFullscreen = null;
// Fonction de basculement plein écran
function toggleFullscreen(frameNum) {
const container = document.getElementById(`frame${frameNum}-container`);
const dashboard = document.getElementById('dashboard');
const btn = document.getElementById(`fullscreen-btn-${frameNum}`);
const configBtn = document.querySelector('.btn-config');
if (currentFullscreen === frameNum) {
// Sortir du plein écran
container.classList.remove('fullscreen-active');
dashboard.classList.remove('fullscreen');
btn.classList.remove('exit');
btn.textContent = '⛶';
configBtn.classList.remove('hidden');
currentFullscreen = null;
// Réafficher toutes les autres vues actives
for (let i = 1; i <= 4; i++) {
const otherContainer = document.getElementById(`frame${i}-container`);
if (otherContainer.classList.contains('active') && i !== frameNum) {
otherContainer.style.display = '';
}
}
} else {
// Entrer en plein écran
// D'abord sortir du plein écran si une autre vue l'est
if (currentFullscreen !== null) {
toggleFullscreen(currentFullscreen);
}
container.classList.add('fullscreen-active');
dashboard.classList.add('fullscreen');
btn.classList.add('exit');
btn.textContent = '✕';
configBtn.classList.add('hidden');
currentFullscreen = frameNum;
// Masquer toutes les autres vues
for (let i = 1; i <= 4; i++) {
if (i !== frameNum) {
const otherContainer = document.getElementById(`frame${i}-container`);
otherContainer.style.display = 'none';
}
}
}
}
// Fonction de zoom individuel
function zoom(frameNum, delta) {
zoomLevels[frameNum] = Math.max(0.5, Math.min(2, zoomLevels[frameNum] + delta));
updateZoom(frameNum);
}
// Mettre à jour l'affichage du zoom
function updateZoom(frameNum) {
const wrapper = document.getElementById(`wrapper${frameNum}`);
const zoomDisplay = document.getElementById(`zoom${frameNum}`);
const scale = zoomLevels[frameNum];
wrapper.style.transform = `scale(${scale})`;
wrapper.style.width = `${100 / scale}%`;
wrapper.style.height = `${100 / scale}%`;
zoomDisplay.textContent = `${Math.round(scale * 100)}%`;
}
// Gestion de la touche Escape pour sortir du plein écran
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' && currentFullscreen !== null) {
toggleFullscreen(currentFullscreen);
}
});
// Charger la config depuis l'ESP32
fetch('/getconfig')
.then(response => response.json())
.then(config => {
applyConfig(config);
});
function applyConfig(config) {
const dashboard = document.getElementById('dashboard');
let count = 0;
// Compter les interfaces configurées
for (let i = 1; i <= 4; i++) {
if (config[`ip${i}`]) count++;
}
// Appliquer le layout
dashboard.className = '';
dashboard.classList.add(`layout-${count}`);
// Configurer les frames
let frameIndex = 1;
for (let i = 1; i <= 4; i++) {
if (config[`ip${i}`]) {
const container = document.getElementById(`frame${frameIndex}-container`);
const frame = document.getElementById(`frame${frameIndex}`);
const label = document.getElementById(`label${frameIndex}`);
container.classList.add('active');
frame.src = `http://${config[`ip${i}`]}`;
label.textContent = config[`name${i}`] || `Interface ${i}`;
frameIndex++;
}
}
}
</script>
</body>
</html>
)rawliteral";
void loadConfig() {
EEPROM.begin(sizeof(Config));
EEPROM.get(0, config);
// Vérifier si config valide
if (String(config.magic) != "RMS") {
// Config invalide, mode AP
isAPMode = true;
}
}
void saveConfig() {
strcpy(config.magic, "RMS");
EEPROM.put(0, config);
EEPROM.commit();
}
void clearConfig() {
strcpy(config.magic, "");
EEPROM.put(0, config);
EEPROM.commit();
}
void startAPMode() {
Serial.println("Démarrage en mode AP...");
WiFi.mode(WIFI_AP);
WiFi.softAP("RMS_Dashboard_Config", "rms12345");
IPAddress IP = WiFi.softAPIP();
Serial.print("AP IP: ");
Serial.println(IP);
}
void handleConfigPage() {
server.send(200, "text/html", config_html);
}
// Variables globales pour l'authentification
bool isAuthenticated = false;
String sessionID = "";
// Générer un ID de session aléatoire
String generateSessionID() {
String id = "";
for (int i = 0; i < 16; i++) {
id += String(random(0, 16), HEX);
}
return id;
}
// Vérifier l'authentification
bool checkAuth() {
// En mode AP, pas d'authentification
if (isAPMode) {
return true;
}
// Si pas de mot de passe configuré, accès libre
if (strlen(config.dashUser) == 0 && strlen(config.dashPass) == 0) {
return true;
}
// Si seulement un des deux est vide, accès libre aussi (config incomplète)
if (strlen(config.dashUser) == 0 || strlen(config.dashPass) == 0) {
return true;
}
// Vérifier le cookie de session
if (server.hasHeader("Cookie")) {
String cookie = server.header("Cookie");
if (cookie.indexOf("session=" + sessionID) != -1 && sessionID != "") {
return true;
}
}
return false;
}
void handleNetworkInfo() {
String json = "{";
if (isAPMode) {
json += "\"isAP\":true,";
json += "\"ip\":\"192.168.4.1\"";
} else {
json += "\"isAP\":false,";
json += "\"ip\":\"" + WiFi.localIP().toString() + "\"";
}
json += "}";
server.send(200, "application/json", json);
}
void handleLogin() {
if (server.method() == HTTP_POST) {
String user = server.arg("user");
String pass = server.arg("pass");
if (user == config.dashUser && pass == config.dashPass) {
// Login réussi
sessionID = generateSessionID();
server.sendHeader("Set-Cookie", "session=" + sessionID + "; Path=/");
server.sendHeader("Location", "/");
server.send(302);
} else {
// Login échoué
server.sendHeader("Location", "/?error=1");
server.send(302);
}
} else {
server.send(200, "text/html", login_html);
}
}
void handleRoot() {
if (isAPMode) {
server.send(200, "text/html", config_html);
} else {
if (!checkAuth()) {
server.send(200, "text/html", login_html);
} else {
server.send(200, "text/html", dashboard_html);
}
}
}
void handleScan() {
int n = WiFi.scanNetworks();
String json = "{\"networks\":[";
for (int i = 0; i < n; i++) {
if (i > 0) json += ",";
String ssid = WiFi.SSID(i);
// Échapper les caractères spéciaux dans le SSID
ssid.replace("\"", "\\\"");
ssid.replace("\\", "\\\\");
json += "{\"ssid\":\"" + ssid + "\",\"rssi\":" + String(WiFi.RSSI(i)) + "}";
}
json += "]}";
server.send(200, "application/json", json);
}
void handleSave() {
if (server.hasArg("plain")) {
DynamicJsonDocument doc(1024);
deserializeJson(doc, server.arg("plain"));
// Sauvegarder la config
strcpy(config.ssid, doc["ssid"]);
strcpy(config.password, doc["password"]);
strcpy(config.dashUser, doc["dashUser"] | "");
strcpy(config.dashPass, doc["dashPass"] | "");
strcpy(config.ip1, doc["ip1"]);
strcpy(config.ip2, doc["ip2"]);
strcpy(config.ip3, doc["ip3"] | "");
strcpy(config.ip4, doc["ip4"] | "");
strcpy(config.name1, doc["name1"] | "Interface 1");
strcpy(config.name2, doc["name2"] | "Interface 2");
strcpy(config.name3, doc["name3"] | "Interface 3");
strcpy(config.name4, doc["name4"] | "Interface 4");
saveConfig();
server.send(200, "text/plain", "OK");
delay(5000);
ESP.restart();
}
}
void handleConfig() {
String json = "{";
json += "\"ssid\":\"" + String(config.ssid) + "\",";
json += "\"ip1\":\"" + String(config.ip1) + "\",";
json += "\"ip2\":\"" + String(config.ip2) + "\",";
json += "\"ip3\":\"" + String(config.ip3) + "\",";
json += "\"ip4\":\"" + String(config.ip4) + "\",";
json += "\"name1\":\"" + String(config.name1) + "\",";
json += "\"name2\":\"" + String(config.name2) + "\",";
json += "\"name3\":\"" + String(config.name3) + "\",";
json += "\"name4\":\"" + String(config.name4) + "\"";
json += "}";
server.send(200, "application/json", json);
}
void handleReset() {
clearConfig();
server.send(200, "text/plain", "Config cleared");
}
void setup() {
Serial.begin(115200);
// Charger la config
loadConfig();
if (isAPMode) {
// Mode AP pour configuration
startAPMode();
} else {
// Mode normal - connexion WiFi
WiFi.begin(config.ssid, config.password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() != WL_CONNECTED) {
// Échec connexion, retour en mode AP
isAPMode = true;
startAPMode();
} else {
Serial.println("\nConnecté!");
Serial.print("IP: ");
Serial.println(WiFi.localIP());
}
}
// Routes
server.on("/", handleRoot);
server.on("/login", handleLogin);
server.on("/config", handleConfigPage); // Page de configuration
server.on("/scan", handleScan);
server.on("/save", HTTP_POST, handleSave);
server.on("/getconfig", handleConfig); // API pour récupérer la config
server.on("/reset", handleReset);
server.on("/networkinfo", handleNetworkInfo);
server.begin();
Serial.println("Serveur démarré");
}
void loop() {
server.handleClient();
}
j ai fait des modifs dans config (bouton retor et rappel des enregistrements d ip et autre)
pour intergrer creez un dossier" webif_multi " et dedans un fichier "webif_multi.ino" avec le contenu du code si dessus
Cdlt
ESP32Wroom, Triac 40A "BTA40", Source UxIx2, Cumulus 300L 3000W.
Sonde temperature sur radiateur triac mise en route ventilateur a 25°
réactivité 30 seuil -50
2 esp32 pour gestion charge batteries
14 panneaux de 410wcc en autoconso micro-onduleur APS DS3
Suivi sur Domoticz
Sonde temperature sur radiateur triac mise en route ventilateur a 25°
réactivité 30 seuil -50
2 esp32 pour gestion charge batteries
14 panneaux de 410wcc en autoconso micro-onduleur APS DS3
Suivi sur Domoticz