RE: Petit prog pour esp32 - Philmaz - 29-05-2025
Mon esp reste en ap mode
J'ai oublié quelque chose?
RE: Petit prog pour esp32 - grostoto - 29-05-2025
attention, la page ne rafraichi pas toute seule.
il faut aller chercher l'adresse ip, et se connecté dessus.
c'est vrai que sur le routeur, on est habitué à avoir la nlle adresse affichée.. (et cliquable je crois).
RE: Petit prog pour esp32 - Philmaz - 30-05-2025
Bonjour grostoto
Une fois le téléversement fait et les renseignement demandés c'est à dire
Mon ssid
Mon mot de passe
Mes interfaces (adresses et noms)
Sauvegarde et redémarrage
J'ouvre le moniteur série et (voir fichier joint)
Sur ma liste de matériels connectés pas de nouvelle adresse ip et mon esp est toujours dans la liste de mes réseau wifi joignable à l'adresse 192.168.4.1
J'oubli certainement un truc évident......
RE: Petit prog pour esp32 - lucky - 30-05-2025
(30-05-2025, 07:26 AM)Philmaz a écrit : Bonjour grostoto
Une fois le téléversement fait et les renseignement demandés c'est à dire
Mon ssid
Mon mot de passe
Mes interfaces (adresses et noms)
Sauvegarde et redémarrage
J'ouvre le moniteur série et (voir fichier joint)
Sur ma liste de matériels connectés pas de nouvelle adresse ip et mon esp est toujours dans la liste de mes réseau wifi joignable à l'adresse 192.168.4.1
J'oubli certainement un truc évident......
slt
tu scannes le reseau ? et tu mets pass wifi ? puis enregistre ?
normalement tu devraisq voir la new ip sur la console
je vais essayer de faire afficher la nouvelle ip
RE: Petit prog pour esp32 - grostoto - 30-05-2025
Salut
a oui, ça serait cool...
Comme le routeur de André.
RE: Petit prog pour esp32 - Philmaz - 30-05-2025
Desolé mais tjrs pas compris 
Pass wifi ?
Voilà comment je fais.
Ca veut dire que esp ne se connecte pas au réseau local ?
J'ai essayé avec plusieurs esp.
RE: Petit prog pour esp32 - lucky - 30-05-2025
(30-05-2025, 08:19 AM)Philmaz a écrit : Desolé mais tjrs pas compris 
Pass wifi ?
Voilà comment je fais.
Ca veut dire que esp ne se connecte pas au réseau local ?
J'ai essayé avec plusieurs esp.
oui c est ca , et apres sauvegarde l esp va redémarrer et sur la console la nouvelle ip de connexion sera affichée
si revient en mode AP c est qu il ne se connecte pas au reseau ......(probleme wifi ou autre )
montre le log de la console sur un cycle complet
RE: Petit prog pour esp32 - Philmaz - 30-05-2025
(30-05-2025, 08:26 AM)lucky a écrit : (30-05-2025, 08:19 AM)Philmaz a écrit : Desolé mais tjrs pas compris 
Pass wifi ?
Voilà comment je fais.
Ca veut dire que esp ne se connecte pas au réseau local ?
J'ai essayé avec plusieurs esp.
oui c est ca , et apres sauvegarde l esp va redémarrer et sur la console la nouvelle ip de connexion sera affichée
si revient en mode AP c est qu il ne se connecte pas au reseau ......(probleme wifi ou autre )
Pour moi ça ne se passe pas comme pour vous autres.
La seule adresse qui sort c'est
AP IP : 192.168.4.1
Serveur démarré
RE: Petit prog pour esp32 - lucky - 30-05-2025
voili avec affichage ip et cliquable
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;
// Variables globales pour le test d'IP
String testingIP = "";
bool isTestingConnection = false;
unsigned long testStartTime = 0;
// 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.json())
.then(data => {
if (data.status === 'testing') {
document.getElementById('message').innerHTML =
'<div class="info">✅ Configuration sauvegardée!</div>' +
'<div class="loading">Test de connexion au réseau...</div>';
// Commencer à vérifier l'IP
checkIPStatus(config.ssid);
}
})
.catch(err => {
document.getElementById('message').innerHTML =
'<div class="info" style="background: #ff4444;">Erreur de sauvegarde: ' + err + '</div>';
});
}
function checkIPStatus(ssid) {
const checkInterval = setInterval(() => {
fetch('/checkip')
.then(response => response.json())
.then(data => {
if (data.status === 'connected' && data.ip) {
clearInterval(checkInterval);
document.getElementById('message').innerHTML =
'<div class="info">✅ Configuration sauvegardée!</div>' +
'<div class="info" style="background: #4CAF50; margin-top: 10px;">' +
'? Nouvelle adresse IP : <a href="http://' + data.ip + '" style="color: white; font-size: 24px; font-weight: bold;">' + data.ip + '</a></div>' +
'<div class="info">Cliquez sur l\'IP ou notez cette adresse! Redémarrage dans 10 secondes...</div>' +
'<div class="info">Connectez-vous au WiFi "' + ssid +
'" et accédez à <a href="http://' + data.ip + '" style="color: white; font-weight: bold;">http://' + data.ip + '</a></div>';
// Redémarrer après 10 secondes
setTimeout(() => {
window.location.href = 'http://' + data.ip;
}, 10000);
} else if (data.status === 'failed') {
clearInterval(checkInterval);
document.getElementById('message').innerHTML =
'<div class="info" style="background: #ff4444;">❌ Impossible de se connecter au réseau!</div>' +
'<div class="info">Vérifiez le mot de passe WiFi et réessayez.</div>' +
'<div class="info">Redémarrage dans 10 secondes...</div>';
}
// Si status est "testing", on continue à vérifier
})
.catch(err => {
// Si erreur, c'est peut-être que l'ESP32 a redémarré
clearInterval(checkInterval);
});
}, 1000); // Vérifier chaque seconde
}
</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;
// Initialiser la config avec des valeurs vides
memset(&config, 0, sizeof(Config));
strcpy(config.magic, "");
strcpy(config.ssid, "");
strcpy(config.password, "");
strcpy(config.dashUser, "");
strcpy(config.dashPass, "");
strcpy(config.ip1, "");
strcpy(config.ip2, "");
strcpy(config.ip3, "");
strcpy(config.ip4, "");
strcpy(config.name1, "");
strcpy(config.name2, "");
strcpy(config.name3, "");
strcpy(config.name4, "");
}
}
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();
// Démarrer le test de connexion
isTestingConnection = true;
testStartTime = millis();
testingIP = "";
// Mode AP+STA
WiFi.mode(WIFI_AP_STA);
WiFi.softAP("RMS_Dashboard_Config", "rms12345");
WiFi.begin(config.ssid, config.password);
Serial.println("Test de connexion au nouveau réseau...");
// Répondre immédiatement
server.send(200, "application/json", "{\"status\":\"testing\"}");
}
}
// Nouvelle route pour vérifier le statut
void handleCheckIP() {
String response = "{";
if (isTestingConnection) {
if (WiFi.status() == WL_CONNECTED && testingIP.isEmpty()) {
testingIP = WiFi.localIP().toString();
Serial.print("IP obtenue: ");
Serial.println(testingIP);
}
if (!testingIP.isEmpty()) {
response += "\"status\":\"connected\",\"ip\":\"" + testingIP + "\"";
} else if (millis() - testStartTime > 10000) {
response += "\"status\":\"failed\"";
isTestingConnection = false;
} else {
response += "\"status\":\"testing\"";
}
} else {
response += "\"status\":\"idle\"";
}
response += "}";
server.send(200, "application/json", response);
}
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("/checkip", handleCheckIP); // NOUVELLE ROUTE POUR VÉRIFIER L'IP
server.on("/networkinfo", handleNetworkInfo);
server.begin();
Serial.println("Serveur démarré");
}
void loop() {
server.handleClient();
// Si on est en train de tester la connexion, redémarrer après 15 secondes
if (isTestingConnection && millis() - testStartTime > 15000) {
ESP.restart();
}
}
RE: Petit prog pour esp32 - Philmaz - 30-05-2025
(30-05-2025, 08:29 AM)Philmaz a écrit : (30-05-2025, 08:26 AM)lucky a écrit : (30-05-2025, 08:19 AM)Philmaz a écrit : Desolé mais tjrs pas compris 
Pass wifi ?
Voilà comment je fais.
Ca veut dire que esp ne se connecte pas au réseau local ?
J'ai essayé avec plusieurs esp.
oui c est ca , et apres sauvegarde l esp va redémarrer et sur la console la nouvelle ip de connexion sera affichée
si revient en mode AP c est qu il ne se connecte pas au reseau ......(probleme wifi ou autre )
Pour moi ça ne se passe pas comme pour vous autres.
La seule adresse qui sort c'est
AP IP : 192.168.4.1
Serveur démarré
Bon voici les dernières news.
j'ai pris mon pc portable, televersé le code, tout fais comme vous m'avez expliqué et tout fonctionne.
Allez savoir.
Merci pour ce coup de main lucky et grostoto.
Ca fonctionne nickel.
|