Note de ce sujet :
  • Moyenne : 0 (0 vote(s))
  • 1
  • 2
  • 3
  • 4
  • 5
Petit prog pour esp32
#21
Mon esp reste en ap mode
J'ai oublié quelque chose?
Routeur UxIx2, V 14.2 Triac robodyn avec bta 40 déporté sur dissipateur ventilé avec sonde T° commandé en sortie TOR , seconde sonde sur C-E, 12 panneaux sanyo 236wc, onduleur réseau solarmax 6kw. CE 3300w. Installé depuis avril 2024.
Répondre
#22
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).
Répondre
#23
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......


Pièces jointes Miniature(s)
       
Routeur UxIx2, V 14.2 Triac robodyn avec bta 40 déporté sur dissipateur ventilé avec sonde T° commandé en sortie TOR , seconde sonde sur C-E, 12 panneaux sanyo 236wc, onduleur réseau solarmax 6kw. CE 3300w. Installé depuis avril 2024.
Répondre
#24
(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
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
Répondre
#25
Salut
a oui, ça serait cool...
Comme le routeur de André.
Répondre
#26
Desolé mais tjrs pas compris Undecided
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.


Pièces jointes Miniature(s)
   
Routeur UxIx2, V 14.2 Triac robodyn avec bta 40 déporté sur dissipateur ventilé avec sonde T° commandé en sortie TOR , seconde sonde sur C-E, 12 panneaux sanyo 236wc, onduleur réseau solarmax 6kw. CE 3300w. Installé depuis avril 2024.
Répondre
#27
(30-05-2025, 08:19 AM)Philmaz a écrit : Desolé mais tjrs pas compris Undecided
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
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
Répondre
#28
(30-05-2025, 08:26 AM)lucky a écrit :
(30-05-2025, 08:19 AM)Philmaz a écrit : Desolé mais tjrs pas compris Undecided
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é
Routeur UxIx2, V 14.2 Triac robodyn avec bta 40 déporté sur dissipateur ventilé avec sonde T° commandé en sortie TOR , seconde sonde sur C-E, 12 panneaux sanyo 236wc, onduleur réseau solarmax 6kw. CE 3300w. Installé depuis avril 2024.
Répondre
#29
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();
  }
}
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
Répondre
#30
(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 Undecided
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.
Routeur UxIx2, V 14.2 Triac robodyn avec bta 40 déporté sur dissipateur ventilé avec sonde T° commandé en sortie TOR , seconde sonde sur C-E, 12 panneaux sanyo 236wc, onduleur réseau solarmax 6kw. CE 3300w. Installé depuis avril 2024.
Répondre


Atteindre :


Utilisateur(s) parcourant ce sujet : 2 visiteur(s)