Difference between revisions of "Wi-Fi-ESP32-E-Paper"
(→Code Wi-Fi & ESP32 & E-Paper) |
(→Code Wi-Fi & ESP32 & E-Paper) |
||
| Line 103: | Line 103: | ||
- **Redémarrage automatique en mode station** → le XIAO se connecte au réseau configuré. | - **Redémarrage automatique en mode station** → le XIAO se connecte au réseau configuré. | ||
- **Fallback** : si la connexion échoue, il revient en mode AP pour reconfigurer. | - **Fallback** : si la connexion échoue, il revient en mode AP pour reconfigurer. | ||
| + | </pre> | ||
| + | Code Modifié | ||
| + | |||
| + | <pre> | ||
| + | #include <WiFi.h> | ||
| + | #include <WebServer.h> | ||
| + | #include <Preferences.h> | ||
| + | |||
| + | Preferences prefs; | ||
| + | WebServer server(80); | ||
| + | |||
| + | // ---- CONFIG WIFI DOMESTIQUE PAR DÉFAUT ---- | ||
| + | const char* DEFAULT_STA_SSID = "TonSSID"; | ||
| + | const char* DEFAULT_STA_PASS = "TonMotDePasse"; | ||
| + | |||
| + | // ---- CONFIG AP ---- | ||
| + | const char* AP_SSID = "XIAO_Config"; | ||
| + | const char* AP_PASS = "12345678"; | ||
| + | |||
| + | String ssid, pass; | ||
| + | |||
| + | // ---- PAGE HTML DE CONFIG WIFI ---- | ||
| + | const char* configPage = R"rawliteral( | ||
| + | <!DOCTYPE html> | ||
| + | <html lang="fr"> | ||
| + | <head> | ||
| + | <meta charset="UTF-8"> | ||
| + | <title>Configuration WiFi</title> | ||
| + | <style> | ||
| + | body { | ||
| + | font-family: Arial, sans-serif; | ||
| + | background: linear-gradient(135deg, #4c8bf5, #6dd5fa); | ||
| + | height: 100vh; | ||
| + | margin: 0; | ||
| + | display: flex; | ||
| + | justify-content: center; | ||
| + | align-items: center; | ||
| + | } | ||
| + | |||
| + | .card { | ||
| + | background: white; | ||
| + | padding: 25px; | ||
| + | border-radius: 15px; | ||
| + | width: 320px; | ||
| + | box-shadow: 0 8px 20px rgba(0,0,0,0.2); | ||
| + | text-align: center; | ||
| + | } | ||
| + | |||
| + | h2 { | ||
| + | margin-top: 0; | ||
| + | color: #333; | ||
| + | } | ||
| + | |||
| + | input[type="text"], input[type="password"] { | ||
| + | width: 90%; | ||
| + | padding: 10px; | ||
| + | margin: 10px 0; | ||
| + | border-radius: 8px; | ||
| + | border: 1px solid #aaa; | ||
| + | font-size: 16px; | ||
| + | } | ||
| + | |||
| + | input[type="submit"] { | ||
| + | background: #4c8bf5; | ||
| + | color: white; | ||
| + | border: none; | ||
| + | padding: 12px 20px; | ||
| + | border-radius: 8px; | ||
| + | font-size: 16px; | ||
| + | cursor: pointer; | ||
| + | width: 100%; | ||
| + | margin-top: 10px; | ||
| + | } | ||
| + | |||
| + | input[type="submit"]:hover { | ||
| + | background: #3a6fd8; | ||
| + | } | ||
| + | |||
| + | .links { | ||
| + | margin-top: 15px; | ||
| + | font-size: 14px; | ||
| + | } | ||
| + | |||
| + | .links a { | ||
| + | color: #4c8bf5; | ||
| + | text-decoration: none; | ||
| + | } | ||
| + | |||
| + | .links a:hover { | ||
| + | text-decoration: underline; | ||
| + | } | ||
| + | </style> | ||
| + | </head> | ||
| + | <body> | ||
| + | <div class="card"> | ||
| + | <h2>Configuration WiFi</h2> | ||
| + | <form action="/save" method="POST"> | ||
| + | <input type="text" name="ssid" placeholder="Nom du réseau (SSID)" required> | ||
| + | <input type="password" name="pass" placeholder="Mot de passe" required> | ||
| + | <input type="submit" value="Enregistrer"> | ||
| + | </form> | ||
| + | <div class="links"> | ||
| + | <a href="/status">Voir le statut</a> | ||
| + | </div> | ||
| + | </div> | ||
| + | </body> | ||
| + | </html> | ||
| + | )rawliteral"; | ||
| + | |||
| + | // ---- HANDLERS HTTP ---- | ||
| + | |||
| + | void handleRoot() { | ||
| + | server.send(200, "text/html", configPage); | ||
| + | } | ||
| + | |||
| + | void handleSave() { | ||
| + | if (server.hasArg("ssid") && server.hasArg("pass")) { | ||
| + | prefs.begin("wifi", false); | ||
| + | prefs.putString("ssid", server.arg("ssid")); | ||
| + | prefs.putString("pass", server.arg("pass")); | ||
| + | prefs.end(); | ||
| + | |||
| + | String page = R"rawliteral( | ||
| + | <!DOCTYPE html> | ||
| + | <html lang="fr"> | ||
| + | <head> | ||
| + | <meta charset="UTF-8"> | ||
| + | <title>Paramètres enregistrés</title> | ||
| + | <style> | ||
| + | body { | ||
| + | font-family: Arial, sans-serif; | ||
| + | background: linear-gradient(135deg, #4c8bf5, #6dd5fa); | ||
| + | height: 100vh; | ||
| + | margin: 0; | ||
| + | display: flex; | ||
| + | justify-content: center; | ||
| + | align-items: center; | ||
| + | } | ||
| + | .card { | ||
| + | background: white; | ||
| + | padding: 25px; | ||
| + | border-radius: 15px; | ||
| + | width: 320px; | ||
| + | box-shadow: 0 8px 20px rgba(0,0,0,0.2); | ||
| + | text-align: center; | ||
| + | } | ||
| + | h2 { margin-top: 0; color: #333; } | ||
| + | </style> | ||
| + | </head> | ||
| + | <body> | ||
| + | <div class="card"> | ||
| + | <h2>Paramètres sauvegardés</h2> | ||
| + | <p>L'appareil va redémarrer<br>et tenter de se connecter au nouveau réseau.</p> | ||
| + | </div> | ||
| + | </body> | ||
| + | </html> | ||
| + | )rawliteral"; | ||
| + | |||
| + | server.send(200, "text/html", page); | ||
| + | delay(1500); | ||
| + | ESP.restart(); | ||
| + | } else { | ||
| + | server.send(400, "text/plain", "SSID ou mot de passe manquant"); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void handleStatus() { | ||
| + | String mode = ""; | ||
| + | wifi_mode_t currentMode = WiFi.getMode(); | ||
| + | |||
| + | if (currentMode == WIFI_STA) mode = "Station (STA)"; | ||
| + | else if (currentMode == WIFI_AP) mode = "Point d'accès (AP)"; | ||
| + | else if (currentMode == WIFI_AP_STA) mode = "AP + Station (AP_STA)"; | ||
| + | else mode = "Inconnu"; | ||
| + | |||
| + | String page = R"rawliteral( | ||
| + | <!DOCTYPE html> | ||
| + | <html lang="fr"> | ||
| + | <head> | ||
| + | <meta charset="UTF-8"> | ||
| + | <title>Statut WiFi</title> | ||
| + | <style> | ||
| + | body { | ||
| + | font-family: Arial, sans-serif; | ||
| + | background: linear-gradient(135deg, #6dd5fa, #4c8bf5); | ||
| + | height: 100vh; | ||
| + | margin: 0; | ||
| + | display: flex; | ||
| + | justify-content: center; | ||
| + | align-items: center; | ||
| + | } | ||
| + | |||
| + | .card { | ||
| + | background: white; | ||
| + | padding: 25px; | ||
| + | border-radius: 15px; | ||
| + | width: 350px; | ||
| + | box-shadow: 0 8px 20px rgba(0,0,0,0.2); | ||
| + | text-align: center; | ||
| + | } | ||
| + | |||
| + | h2 { | ||
| + | margin-top: 0; | ||
| + | color: #333; | ||
| + | } | ||
| + | |||
| + | .info { | ||
| + | text-align: left; | ||
| + | margin-top: 15px; | ||
| + | font-size: 16px; | ||
| + | } | ||
| + | |||
| + | .info div { | ||
| + | margin-bottom: 8px; | ||
| + | } | ||
| + | |||
| + | .btn { | ||
| + | margin-top: 15px; | ||
| + | display: inline-block; | ||
| + | padding: 10px 20px; | ||
| + | background: #4c8bf5; | ||
| + | color: white; | ||
| + | border-radius: 8px; | ||
| + | text-decoration: none; | ||
| + | font-size: 14px; | ||
| + | } | ||
| + | |||
| + | .btn:hover { | ||
| + | background: #3a6fd8; | ||
| + | } | ||
| + | |||
| + | .btn-danger { | ||
| + | background: #f56d6d; | ||
| + | } | ||
| + | |||
| + | .btn-danger:hover { | ||
| + | background: #d84a4a; | ||
| + | } | ||
| + | </style> | ||
| + | </head> | ||
| + | <body> | ||
| + | <div class="card"> | ||
| + | <h2>Statut WiFi</h2> | ||
| + | <div class="info"> | ||
| + | )rawliteral"; | ||
| + | |||
| + | page += "<div><b>Mode :</b> " + mode + "</div>"; | ||
| + | page += "<div><b>IP (STA) :</b> " + WiFi.localIP().toString() + "</div>"; | ||
| + | page += "<div><b>IP (AP) :</b> " + WiFi.softAPIP().toString() + "</div>"; | ||
| + | |||
| + | if (WiFi.status() == WL_CONNECTED) { | ||
| + | page += "<div><b>RSSI :</b> " + String(WiFi.RSSI()) + " dBm</div>"; | ||
| + | } else { | ||
| + | page += "<div><b>RSSI :</b> Non connecté</div>"; | ||
| + | } | ||
| + | |||
| + | unsigned long ms = millis(); | ||
| + | unsigned long sec = ms / 1000; | ||
| + | unsigned long min = sec / 60; | ||
| + | unsigned long hr = min / 60; | ||
| + | |||
| + | page += "<div><b>Uptime :</b> " + String(hr) + "h " + String(min % 60) + "m " + String(sec % 60) + "s</div>"; | ||
| + | |||
| + | page += R"rawliteral( | ||
| + | </div> | ||
| + | <a class="btn" href="/">Config WiFi</a> | ||
| + | <a class="btn" href="/reboot">Redémarrer</a> | ||
| + | <a class="btn btn-danger" href="/resetwifi">Reset Wi‑Fi</a> | ||
| + | </div> | ||
| + | </body> | ||
| + | </html> | ||
| + | )rawliteral"; | ||
| + | |||
| + | server.send(200, "text/html", page); | ||
| + | } | ||
| + | |||
| + | void handleReboot() { | ||
| + | String page = R"rawliteral( | ||
| + | <!DOCTYPE html> | ||
| + | <html lang="fr"> | ||
| + | <head> | ||
| + | <meta charset="UTF-8"> | ||
| + | <title>Redémarrage</title> | ||
| + | <style> | ||
| + | body { | ||
| + | font-family: Arial, sans-serif; | ||
| + | background: linear-gradient(135deg, #4c8bf5, #6dd5fa); | ||
| + | height: 100vh; | ||
| + | margin: 0; | ||
| + | display: flex; | ||
| + | justify-content: center; | ||
| + | align-items: center; | ||
| + | } | ||
| + | |||
| + | .card { | ||
| + | background: white; | ||
| + | padding: 25px; | ||
| + | border-radius: 15px; | ||
| + | width: 320px; | ||
| + | box-shadow: 0 8px 20px rgba(0,0,0,0.2); | ||
| + | text-align: center; | ||
| + | } | ||
| + | |||
| + | h2 { | ||
| + | margin-top: 0; | ||
| + | color: #333; | ||
| + | } | ||
| + | </style> | ||
| + | </head> | ||
| + | <body> | ||
| + | <div class="card"> | ||
| + | <h2>Redémarrage en cours…</h2> | ||
| + | <p>L'appareil va redémarrer dans quelques secondes.</p> | ||
| + | </div> | ||
| + | </body> | ||
| + | </html> | ||
| + | )rawliteral"; | ||
| + | |||
| + | server.send(200, "text/html", page); | ||
| + | delay(1500); | ||
| + | ESP.restart(); | ||
| + | } | ||
| + | |||
| + | void handleResetWiFi() { | ||
| + | // Effacer les identifiants WiFi stockés | ||
| + | prefs.begin("wifi", false); | ||
| + | prefs.clear(); | ||
| + | prefs.end(); | ||
| + | |||
| + | String page = R"rawliteral( | ||
| + | <!DOCTYPE html> | ||
| + | <html lang="fr"> | ||
| + | <head> | ||
| + | <meta charset="UTF-8"> | ||
| + | <title>Reset WiFi</title> | ||
| + | <style> | ||
| + | body { | ||
| + | font-family: Arial, sans-serif; | ||
| + | background: linear-gradient(135deg, #f56d6d, #fa9a6d); | ||
| + | height: 100vh; | ||
| + | margin: 0; | ||
| + | display: flex; | ||
| + | justify-content: center; | ||
| + | align-items: center; | ||
| + | } | ||
| + | |||
| + | .card { | ||
| + | background: white; | ||
| + | padding: 25px; | ||
| + | border-radius: 15px; | ||
| + | width: 320px; | ||
| + | box-shadow: 0 8px 20px rgba(0,0,0,0.2); | ||
| + | text-align: center; | ||
| + | } | ||
| + | |||
| + | h2 { | ||
| + | margin-top: 0; | ||
| + | color: #333; | ||
| + | } | ||
| + | </style> | ||
| + | </head> | ||
| + | <body> | ||
| + | <div class="card"> | ||
| + | <h2>Réinitialisation WiFi…</h2> | ||
| + | <p>Les paramètres WiFi ont été effacés.<br>Redémarrage en cours…</p> | ||
| + | </div> | ||
| + | </body> | ||
| + | </html> | ||
| + | )rawliteral"; | ||
| + | |||
| + | server.send(200, "text/html", page); | ||
| + | |||
| + | // Résumé sur le moniteur série | ||
| + | Serial.println("\n===== RESET WIFI ====="); | ||
| + | Serial.println("IP STA : " + WiFi.localIP().toString()); | ||
| + | Serial.println("IP AP : " + WiFi.softAPIP().toString()); | ||
| + | Serial.println("AP SSID : " + String(AP_SSID)); | ||
| + | Serial.println("AP PASS : " + String(AP_PASS)); | ||
| + | |||
| + | if (WiFi.status() == WL_CONNECTED) | ||
| + | Serial.println("RSSI : " + String(WiFi.RSSI()) + " dBm"); | ||
| + | else | ||
| + | Serial.println("RSSI : Non connecté"); | ||
| + | |||
| + | Serial.println("=======================\n"); | ||
| + | |||
| + | delay(1500); | ||
| + | ESP.restart(); | ||
| + | } | ||
| + | |||
| + | // ---- LOGIQUE WIFI ---- | ||
| + | |||
| + | bool connectToWiFi() { | ||
| + | // Charger les valeurs enregistrées (ou défaut) | ||
| + | prefs.begin("wifi", true); | ||
| + | ssid = prefs.getString("ssid", DEFAULT_STA_SSID); | ||
| + | pass = prefs.getString("pass", DEFAULT_STA_PASS); | ||
| + | prefs.end(); | ||
| + | |||
| + | Serial.print("Connexion à "); Serial.println(ssid); | ||
| + | |||
| + | WiFi.begin(ssid.c_str(), pass.c_str()); | ||
| + | |||
| + | unsigned long start = millis(); | ||
| + | while (WiFi.status() != WL_CONNECTED && millis() - start < 10000) { | ||
| + | delay(500); | ||
| + | Serial.print("."); | ||
| + | } | ||
| + | |||
| + | if (WiFi.status() == WL_CONNECTED) { | ||
| + | Serial.println("\n[WiFi] Connecté en STA"); | ||
| + | Serial.println("IP STA : " + WiFi.localIP().toString()); | ||
| + | Serial.println("RSSI : " + String(WiFi.RSSI()) + " dBm"); | ||
| + | return true; | ||
| + | } else { | ||
| + | Serial.println("\n[WiFi] Échec connexion STA"); | ||
| + | return false; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // ---- SETUP / LOOP ---- | ||
| + | |||
| + | void setup() { | ||
| + | Serial.begin(115200); | ||
| + | delay(500); | ||
| + | Serial.println("\n==== DÉMARRAGE XIAO ESP32C3 ===="); | ||
| + | |||
| + | // Mode AP + STA | ||
| + | WiFi.mode(WIFI_AP_STA); | ||
| + | |||
| + | // Lancer AP | ||
| + | WiFi.softAP(AP_SSID, AP_PASS); | ||
| + | Serial.println("[WiFi] AP actif"); | ||
| + | Serial.println(" SSID : " + String(AP_SSID)); | ||
| + | Serial.println(" PASS : " + String(AP_PASS)); | ||
| + | Serial.println(" IP AP: " + WiFi.softAPIP().toString()); | ||
| + | |||
| + | // Tenter connexion STA | ||
| + | connectToWiFi(); | ||
| + | |||
| + | // Routes HTTP | ||
| + | server.on("/", handleRoot); | ||
| + | server.on("/save", HTTP_POST, handleSave); | ||
| + | server.on("/status", handleStatus); | ||
| + | server.on("/reboot", handleReboot); | ||
| + | server.on("/resetwifi", handleResetWiFi); | ||
| + | |||
| + | server.begin(); | ||
| + | Serial.println("[HTTP] Serveur web démarré"); | ||
| + | } | ||
| + | |||
| + | void loop() { | ||
| + | server.handleClient(); | ||
| + | } | ||
</pre> | </pre> | ||
Revision as of 18:52, 19 December 2025
Code Wi-Fi & ESP32 & E-Paper
Wi-Fi-ESP32-E-Paper
#include <WiFi.h>
#include <WebServer.h>
#include <Preferences.h>
Preferences prefs;
WebServer server(80);
String ssid, pass;
const char* configPage = R"rawliteral(
<!DOCTYPE html>
<html>
<body>
<h2>Configuration WiFi</h2>
<form action="/save" method="POST">
SSID: <input type="text" name="ssid"><br>
Password: <input type="text" name="pass"><br>
<input type="submit" value="Save">
</form>
</body>
</html>
)rawliteral";
void handleRoot() {
server.send(200, "text/html", configPage);
}
void handleSave() {
if (server.hasArg("ssid") && server.hasArg("pass")) {
ssid = server.arg("ssid");
pass = server.arg("pass");
prefs.begin("wifi", false);
prefs.putString("ssid", ssid);
prefs.putString("pass", pass);
prefs.end();
server.send(200, "text/html", "Paramètres sauvegardés. Redémarrage...");
delay(2000);
ESP.restart();
}
}
bool connectToWiFi() {
prefs.begin("wifi", true);
ssid = prefs.getString("ssid", "");
pass = prefs.getString("pass", "");
prefs.end();
if (ssid == "") return false;
WiFi.begin(ssid.c_str(), pass.c_str());
Serial.print("Connexion à "); Serial.println(ssid);
unsigned long start = millis();
while (WiFi.status() != WL_CONNECTED && millis() - start < 10000) {
delay(500);
Serial.print(".");
}
return WiFi.status() == WL_CONNECTED;
}
void startAP() {
WiFi.softAP("XIAO_Config", "12345678");
Serial.println("AP démarré. IP: " + WiFi.softAPIP().toString());
server.on("/", handleRoot);
server.on("/save", HTTP_POST, handleSave);
server.begin();
}
void setup() {
Serial.begin(115200);
if (!connectToWiFi()) {
Serial.println("Échec connexion. Passage en mode AP.");
startAP();
} else {
Serial.println("Connecté au WiFi. IP: " + WiFi.localIP().toString());
// Ici vous pouvez lancer un serveur web normal ou autre logique
}
}
void loop() {
server.handleClient();
}
## ⚙️ Fonctionnement - **Premier démarrage** : pas de SSID enregistré → le module crée un AP `XIAO_Config`. - **Page web** : accessible via l’IP du point d’accès (souvent `192.168.4.1`). - **Sauvegarde** : SSID et mot de passe sont stockés dans `Preferences`. - **Redémarrage** : le module tente de se connecter au Wi Fi enregistré. - **Fallback** : si la connexion échoue, retour en mode AP pour reconfigurer.
- **Mode AP (point d’accès)** au démarrage → permet de configurer les paramètres Wi Fi via une page web. - **Sauvegarde des paramètres** (SSID, mot de passe, etc.) dans la mémoire non volatile (Preferences). - **Redémarrage automatique en mode station** → le XIAO se connecte au réseau configuré. - **Fallback** : si la connexion échoue, il revient en mode AP pour reconfigurer.
Code Modifié
#include <WiFi.h>
#include <WebServer.h>
#include <Preferences.h>
Preferences prefs;
WebServer server(80);
// ---- CONFIG WIFI DOMESTIQUE PAR DÉFAUT ----
const char* DEFAULT_STA_SSID = "TonSSID";
const char* DEFAULT_STA_PASS = "TonMotDePasse";
// ---- CONFIG AP ----
const char* AP_SSID = "XIAO_Config";
const char* AP_PASS = "12345678";
String ssid, pass;
// ---- PAGE HTML DE CONFIG WIFI ----
const char* configPage = R"rawliteral(
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Configuration WiFi</title>
<style>
body {
font-family: Arial, sans-serif;
background: linear-gradient(135deg, #4c8bf5, #6dd5fa);
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
}
.card {
background: white;
padding: 25px;
border-radius: 15px;
width: 320px;
box-shadow: 0 8px 20px rgba(0,0,0,0.2);
text-align: center;
}
h2 {
margin-top: 0;
color: #333;
}
input[type="text"], input[type="password"] {
width: 90%;
padding: 10px;
margin: 10px 0;
border-radius: 8px;
border: 1px solid #aaa;
font-size: 16px;
}
input[type="submit"] {
background: #4c8bf5;
color: white;
border: none;
padding: 12px 20px;
border-radius: 8px;
font-size: 16px;
cursor: pointer;
width: 100%;
margin-top: 10px;
}
input[type="submit"]:hover {
background: #3a6fd8;
}
.links {
margin-top: 15px;
font-size: 14px;
}
.links a {
color: #4c8bf5;
text-decoration: none;
}
.links a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="card">
<h2>Configuration WiFi</h2>
<form action="/save" method="POST">
<input type="text" name="ssid" placeholder="Nom du réseau (SSID)" required>
<input type="password" name="pass" placeholder="Mot de passe" required>
<input type="submit" value="Enregistrer">
</form>
<div class="links">
<a href="/status">Voir le statut</a>
</div>
</div>
</body>
</html>
)rawliteral";
// ---- HANDLERS HTTP ----
void handleRoot() {
server.send(200, "text/html", configPage);
}
void handleSave() {
if (server.hasArg("ssid") && server.hasArg("pass")) {
prefs.begin("wifi", false);
prefs.putString("ssid", server.arg("ssid"));
prefs.putString("pass", server.arg("pass"));
prefs.end();
String page = R"rawliteral(
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Paramètres enregistrés</title>
<style>
body {
font-family: Arial, sans-serif;
background: linear-gradient(135deg, #4c8bf5, #6dd5fa);
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
}
.card {
background: white;
padding: 25px;
border-radius: 15px;
width: 320px;
box-shadow: 0 8px 20px rgba(0,0,0,0.2);
text-align: center;
}
h2 { margin-top: 0; color: #333; }
</style>
</head>
<body>
<div class="card">
<h2>Paramètres sauvegardés</h2>
<p>L'appareil va redémarrer<br>et tenter de se connecter au nouveau réseau.</p>
</div>
</body>
</html>
)rawliteral";
server.send(200, "text/html", page);
delay(1500);
ESP.restart();
} else {
server.send(400, "text/plain", "SSID ou mot de passe manquant");
}
}
void handleStatus() {
String mode = "";
wifi_mode_t currentMode = WiFi.getMode();
if (currentMode == WIFI_STA) mode = "Station (STA)";
else if (currentMode == WIFI_AP) mode = "Point d'accès (AP)";
else if (currentMode == WIFI_AP_STA) mode = "AP + Station (AP_STA)";
else mode = "Inconnu";
String page = R"rawliteral(
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Statut WiFi</title>
<style>
body {
font-family: Arial, sans-serif;
background: linear-gradient(135deg, #6dd5fa, #4c8bf5);
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
}
.card {
background: white;
padding: 25px;
border-radius: 15px;
width: 350px;
box-shadow: 0 8px 20px rgba(0,0,0,0.2);
text-align: center;
}
h2 {
margin-top: 0;
color: #333;
}
.info {
text-align: left;
margin-top: 15px;
font-size: 16px;
}
.info div {
margin-bottom: 8px;
}
.btn {
margin-top: 15px;
display: inline-block;
padding: 10px 20px;
background: #4c8bf5;
color: white;
border-radius: 8px;
text-decoration: none;
font-size: 14px;
}
.btn:hover {
background: #3a6fd8;
}
.btn-danger {
background: #f56d6d;
}
.btn-danger:hover {
background: #d84a4a;
}
</style>
</head>
<body>
<div class="card">
<h2>Statut WiFi</h2>
<div class="info">
)rawliteral";
page += "<div><b>Mode :</b> " + mode + "</div>";
page += "<div><b>IP (STA) :</b> " + WiFi.localIP().toString() + "</div>";
page += "<div><b>IP (AP) :</b> " + WiFi.softAPIP().toString() + "</div>";
if (WiFi.status() == WL_CONNECTED) {
page += "<div><b>RSSI :</b> " + String(WiFi.RSSI()) + " dBm</div>";
} else {
page += "<div><b>RSSI :</b> Non connecté</div>";
}
unsigned long ms = millis();
unsigned long sec = ms / 1000;
unsigned long min = sec / 60;
unsigned long hr = min / 60;
page += "<div><b>Uptime :</b> " + String(hr) + "h " + String(min % 60) + "m " + String(sec % 60) + "s</div>";
page += R"rawliteral(
</div>
<a class="btn" href="/">Config WiFi</a>
<a class="btn" href="/reboot">Redémarrer</a>
<a class="btn btn-danger" href="/resetwifi">Reset Wi‑Fi</a>
</div>
</body>
</html>
)rawliteral";
server.send(200, "text/html", page);
}
void handleReboot() {
String page = R"rawliteral(
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Redémarrage</title>
<style>
body {
font-family: Arial, sans-serif;
background: linear-gradient(135deg, #4c8bf5, #6dd5fa);
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
}
.card {
background: white;
padding: 25px;
border-radius: 15px;
width: 320px;
box-shadow: 0 8px 20px rgba(0,0,0,0.2);
text-align: center;
}
h2 {
margin-top: 0;
color: #333;
}
</style>
</head>
<body>
<div class="card">
<h2>Redémarrage en cours…</h2>
<p>L'appareil va redémarrer dans quelques secondes.</p>
</div>
</body>
</html>
)rawliteral";
server.send(200, "text/html", page);
delay(1500);
ESP.restart();
}
void handleResetWiFi() {
// Effacer les identifiants WiFi stockés
prefs.begin("wifi", false);
prefs.clear();
prefs.end();
String page = R"rawliteral(
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Reset WiFi</title>
<style>
body {
font-family: Arial, sans-serif;
background: linear-gradient(135deg, #f56d6d, #fa9a6d);
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
}
.card {
background: white;
padding: 25px;
border-radius: 15px;
width: 320px;
box-shadow: 0 8px 20px rgba(0,0,0,0.2);
text-align: center;
}
h2 {
margin-top: 0;
color: #333;
}
</style>
</head>
<body>
<div class="card">
<h2>Réinitialisation WiFi…</h2>
<p>Les paramètres WiFi ont été effacés.<br>Redémarrage en cours…</p>
</div>
</body>
</html>
)rawliteral";
server.send(200, "text/html", page);
// Résumé sur le moniteur série
Serial.println("\n===== RESET WIFI =====");
Serial.println("IP STA : " + WiFi.localIP().toString());
Serial.println("IP AP : " + WiFi.softAPIP().toString());
Serial.println("AP SSID : " + String(AP_SSID));
Serial.println("AP PASS : " + String(AP_PASS));
if (WiFi.status() == WL_CONNECTED)
Serial.println("RSSI : " + String(WiFi.RSSI()) + " dBm");
else
Serial.println("RSSI : Non connecté");
Serial.println("=======================\n");
delay(1500);
ESP.restart();
}
// ---- LOGIQUE WIFI ----
bool connectToWiFi() {
// Charger les valeurs enregistrées (ou défaut)
prefs.begin("wifi", true);
ssid = prefs.getString("ssid", DEFAULT_STA_SSID);
pass = prefs.getString("pass", DEFAULT_STA_PASS);
prefs.end();
Serial.print("Connexion à "); Serial.println(ssid);
WiFi.begin(ssid.c_str(), pass.c_str());
unsigned long start = millis();
while (WiFi.status() != WL_CONNECTED && millis() - start < 10000) {
delay(500);
Serial.print(".");
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\n[WiFi] Connecté en STA");
Serial.println("IP STA : " + WiFi.localIP().toString());
Serial.println("RSSI : " + String(WiFi.RSSI()) + " dBm");
return true;
} else {
Serial.println("\n[WiFi] Échec connexion STA");
return false;
}
}
// ---- SETUP / LOOP ----
void setup() {
Serial.begin(115200);
delay(500);
Serial.println("\n==== DÉMARRAGE XIAO ESP32C3 ====");
// Mode AP + STA
WiFi.mode(WIFI_AP_STA);
// Lancer AP
WiFi.softAP(AP_SSID, AP_PASS);
Serial.println("[WiFi] AP actif");
Serial.println(" SSID : " + String(AP_SSID));
Serial.println(" PASS : " + String(AP_PASS));
Serial.println(" IP AP: " + WiFi.softAPIP().toString());
// Tenter connexion STA
connectToWiFi();
// Routes HTTP
server.on("/", handleRoot);
server.on("/save", HTTP_POST, handleSave);
server.on("/status", handleStatus);
server.on("/reboot", handleReboot);
server.on("/resetwifi", handleResetWiFi);
server.begin();
Serial.println("[HTTP] Serveur web démarré");
}
void loop() {
server.handleClient();
}