Difference between revisions of "Wi-Fi-ESP32-E-Paper"
(→Code Wi-Fi & ESP32 & E-Paper) |
(→Code Wi-Fi & ESP32 & E-Paper) |
||
| (3 intermediate revisions by 2 users not shown) | |||
| Line 104: | Line 104: | ||
- **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> | </pre> | ||
| + | |||
Code Modifié | Code Modifié | ||
| + | |||
| + | [[File:CONFIGURATION-WI-FI.PNG|250px]] | ||
| + | [[File:STATUS-WI-FI.PNG|250px]] | ||
| + | [[File:OUTPUT SERIAL-Wi-Fi.PNG|250px]] | ||
| + | |||
| + | |||
<pre> | <pre> | ||
| Line 557: | Line 564: | ||
server.handleClient(); | server.handleClient(); | ||
} | } | ||
| + | </pre> | ||
| + | |||
| + | <pre> | ||
| + | ✅ Mode AP + STA simultané | ||
| + | |||
| + | ✅ STA avec SSID/mot de passe par défaut, surchargeables via la page de config | ||
| + | |||
| + | ✅ AP fixe : SSID XIAO_Config / mot de passe 12345678 | ||
| + | |||
| + | ✅ Page de configuration Wi‑Fi stylée (/) | ||
| + | |||
| + | ✅ Page de statut (/status) : IP STA, IP AP, RSSI, mode, uptime | ||
| + | |||
| + | ✅ Bouton Reboot (/reboot) | ||
| + | |||
| + | ✅ Bouton Reset Wi‑Fi (/resetwifi) qui efface Preferences + reboot | ||
| + | |||
| + | ✅ Résumé sur le moniteur série au reset Wi‑Fi | ||
| + | </pre> | ||
| + | |||
| + | === Code Wi-Fi & ESP32 & E-Paper 3 onglets === | ||
| + | |||
| + | <pre> | ||
| + | #include <WiFi.h> | ||
| + | #include <WebServer.h> | ||
| + | #include <Preferences.h> | ||
| + | #include "TimeDisplayEPaper.h" // ✅ Ajout pour l’e-paper | ||
| + | |||
| + | 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() { | ||
| + | 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); | ||
| + | |||
| + | 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() { | ||
| + | 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 ===="); | ||
| + | |||
| + | WiFi.mode(WIFI_AP_STA); | ||
| + | |||
| + | 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()); | ||
| + | |||
| + | connectToWiFi(); | ||
| + | |||
| + | 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é"); | ||
| + | |||
| + | initEPaper(); // ✅ Ajout | ||
| + | } | ||
| + | |||
| + | void loop() { | ||
| + | server.handleClient(); | ||
| + | updateEPaperTime(); // ✅ Ajout | ||
| + | } | ||
| + | </pre> | ||
| + | |||
| + | <pre> | ||
| + | // Onglet TimeDisplayEPaper.h | ||
| + | #pragma once | ||
| + | #include <time.h> | ||
| + | #include <TFT_eSPI.h> | ||
| + | #include <SPI.h> | ||
| + | #include <WiFi.h> | ||
| + | |||
| + | #ifdef EPAPER_ENABLE | ||
| + | EPaper epaper = EPaper(); // Pins définis dans User_Setup.h | ||
| + | #endif | ||
| + | |||
| + | // ⚙️ Paramètres NTP | ||
| + | const char* ntpServer = "pool.ntp.org"; | ||
| + | const long gmtOffset_sec = 3600; // +1h (Suisse en hiver) | ||
| + | const int daylightOffset_sec = 3600; // +1h (DST été) | ||
| + | |||
| + | // Variables pour éviter scintillement | ||
| + | int lastMinute = -1; | ||
| + | |||
| + | // --- Initialisation de l’e-paper --- | ||
| + | void initEPaper() { | ||
| + | #ifdef EPAPER_ENABLE | ||
| + | epaper.begin(); | ||
| + | epaper.setRotation(1); | ||
| + | epaper.fillScreen(TFT_WHITE); | ||
| + | epaper.setTextColor(TFT_BLACK, TFT_WHITE); | ||
| + | epaper.update(); | ||
| + | epaper.sleep(); | ||
| + | #endif | ||
| + | |||
| + | // Initialisation NTP | ||
| + | configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); | ||
| + | } | ||
| + | |||
| + | // --- Fonction pour dessiner un pictogramme Wi-Fi --- | ||
| + | void drawWiFiIcon(int x, int y, int rssi) { | ||
| + | int bars = 0; | ||
| + | if (rssi > -50) bars = 4; | ||
| + | else if (rssi > -60) bars = 3; | ||
| + | else if (rssi > -70) bars = 2; | ||
| + | else if (rssi > -80) bars = 1; | ||
| + | else bars = 0; | ||
| + | |||
| + | int barWidth = 6; | ||
| + | int spacing = 3; | ||
| + | for (int i = 0; i < 4; i++) { | ||
| + | int barHeight = (i+1) * 6; | ||
| + | int bx = x + i * (barWidth + spacing); | ||
| + | int by = y + (24 - barHeight); | ||
| + | if (i < bars) { | ||
| + | epaper.fillRect(bx, by, barWidth, barHeight, TFT_BLACK); | ||
| + | } else { | ||
| + | epaper.drawRect(bx, by, barWidth, barHeight, TFT_BLACK); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // --- Mise à jour de l’affichage --- | ||
| + | void updateEPaperTime() { | ||
| + | struct tm timeinfo; | ||
| + | if (!getLocalTime(&timeinfo)) { | ||
| + | Serial.println("Erreur récupération heure NTP"); | ||
| + | return; | ||
| + | } | ||
| + | |||
| + | if (timeinfo.tm_min != lastMinute) { | ||
| + | lastMinute = timeinfo.tm_min; | ||
| + | |||
| + | #ifdef EPAPER_ENABLE | ||
| + | epaper.fillScreen(TFT_WHITE); | ||
| + | |||
| + | // --- Affichage DATE --- | ||
| + | epaper.setTextDatum(TC_DATUM); | ||
| + | epaper.drawString( | ||
| + | String(timeinfo.tm_mday) + "/" + | ||
| + | String(timeinfo.tm_mon+1) + "/" + | ||
| + | String(timeinfo.tm_year+1900), | ||
| + | epaper.width()/2, 30, 4 | ||
| + | ); | ||
| + | |||
| + | // --- Affichage HEURE --- | ||
| + | char buffer[6]; | ||
| + | sprintf(buffer, "%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min); | ||
| + | epaper.setTextDatum(MC_DATUM); | ||
| + | epaper.drawString(buffer, epaper.width()/2, epaper.height()/2, 7); | ||
| + | |||
| + | // --- Encadré infos réseau --- | ||
| + | int boxX = 5; | ||
| + | int boxY = epaper.height() - 70; | ||
| + | int boxW = epaper.width() - 10; | ||
| + | int boxH = 60; | ||
| + | |||
| + | epaper.fillRect(boxX, boxY, boxW, boxH, TFT_LIGHTGREY); | ||
| + | epaper.drawRect(boxX, boxY, boxW, boxH, TFT_BLACK); | ||
| + | |||
| + | epaper.setTextColor(TFT_BLACK, TFT_LIGHTGREY); | ||
| + | epaper.setTextDatum(TL_DATUM); | ||
| + | epaper.drawString("IP STA: " + WiFi.localIP().toString(), boxX + 10, boxY + 12, 2); | ||
| + | |||
| + | // --- Pictogramme Wi-Fi centré --- | ||
| + | int iconX = boxX + (boxW/2) - 15; | ||
| + | int iconY = boxY + 5; | ||
| + | drawWiFiIcon(iconX, iconY, WiFi.RSSI()); | ||
| + | |||
| + | // --- RSSI sous l’icône --- | ||
| + | epaper.setTextDatum(TC_DATUM); | ||
| + | epaper.drawString("RSSI: " + String(WiFi.RSSI()) + " dBm", boxX + boxW/2, boxY + 40, 2); | ||
| + | |||
| + | epaper.update(); | ||
| + | #endif | ||
| + | |||
| + | // --- Sortie série --- | ||
| + | Serial.printf("Heure actuelle : %02d:%02d:%02d\n", | ||
| + | timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec); | ||
| + | Serial.println("IP STA : " + WiFi.localIP().toString()); | ||
| + | Serial.println("RSSI : " + String(WiFi.RSSI()) + " dBm"); | ||
| + | } | ||
| + | } | ||
| + | </pre> | ||
| + | |||
| + | <pre> | ||
| + | // onglet driver.h | ||
| + | // driver.h file | ||
| + | #define BOARD_SCREEN_COMBO 505 // 1.54 inch monochrome ePaper Screen (SSD1681) | ||
| + | #define USE_XIAO_EPAPER_BREAKOUT_BOARD | ||
</pre> | </pre> | ||
Latest revision as of 00:06, 20 December 2025
Code Wi-Fi & ESP32 & E-Paper[edit]
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();
}
✅ Mode AP + STA simultané ✅ STA avec SSID/mot de passe par défaut, surchargeables via la page de config ✅ AP fixe : SSID XIAO_Config / mot de passe 12345678 ✅ Page de configuration Wi‑Fi stylée (/) ✅ Page de statut (/status) : IP STA, IP AP, RSSI, mode, uptime ✅ Bouton Reboot (/reboot) ✅ Bouton Reset Wi‑Fi (/resetwifi) qui efface Preferences + reboot ✅ Résumé sur le moniteur série au reset Wi‑Fi
Code Wi-Fi & ESP32 & E-Paper 3 onglets[edit]
#include <WiFi.h>
#include <WebServer.h>
#include <Preferences.h>
#include "TimeDisplayEPaper.h" // ✅ Ajout pour l’e-paper
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() {
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);
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() {
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 ====");
WiFi.mode(WIFI_AP_STA);
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());
connectToWiFi();
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é");
initEPaper(); // ✅ Ajout
}
void loop() {
server.handleClient();
updateEPaperTime(); // ✅ Ajout
}
// Onglet TimeDisplayEPaper.h
#pragma once
#include <time.h>
#include <TFT_eSPI.h>
#include <SPI.h>
#include <WiFi.h>
#ifdef EPAPER_ENABLE
EPaper epaper = EPaper(); // Pins définis dans User_Setup.h
#endif
// ⚙️ Paramètres NTP
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 3600; // +1h (Suisse en hiver)
const int daylightOffset_sec = 3600; // +1h (DST été)
// Variables pour éviter scintillement
int lastMinute = -1;
// --- Initialisation de l’e-paper ---
void initEPaper() {
#ifdef EPAPER_ENABLE
epaper.begin();
epaper.setRotation(1);
epaper.fillScreen(TFT_WHITE);
epaper.setTextColor(TFT_BLACK, TFT_WHITE);
epaper.update();
epaper.sleep();
#endif
// Initialisation NTP
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
}
// --- Fonction pour dessiner un pictogramme Wi-Fi ---
void drawWiFiIcon(int x, int y, int rssi) {
int bars = 0;
if (rssi > -50) bars = 4;
else if (rssi > -60) bars = 3;
else if (rssi > -70) bars = 2;
else if (rssi > -80) bars = 1;
else bars = 0;
int barWidth = 6;
int spacing = 3;
for (int i = 0; i < 4; i++) {
int barHeight = (i+1) * 6;
int bx = x + i * (barWidth + spacing);
int by = y + (24 - barHeight);
if (i < bars) {
epaper.fillRect(bx, by, barWidth, barHeight, TFT_BLACK);
} else {
epaper.drawRect(bx, by, barWidth, barHeight, TFT_BLACK);
}
}
}
// --- Mise à jour de l’affichage ---
void updateEPaperTime() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Erreur récupération heure NTP");
return;
}
if (timeinfo.tm_min != lastMinute) {
lastMinute = timeinfo.tm_min;
#ifdef EPAPER_ENABLE
epaper.fillScreen(TFT_WHITE);
// --- Affichage DATE ---
epaper.setTextDatum(TC_DATUM);
epaper.drawString(
String(timeinfo.tm_mday) + "/" +
String(timeinfo.tm_mon+1) + "/" +
String(timeinfo.tm_year+1900),
epaper.width()/2, 30, 4
);
// --- Affichage HEURE ---
char buffer[6];
sprintf(buffer, "%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min);
epaper.setTextDatum(MC_DATUM);
epaper.drawString(buffer, epaper.width()/2, epaper.height()/2, 7);
// --- Encadré infos réseau ---
int boxX = 5;
int boxY = epaper.height() - 70;
int boxW = epaper.width() - 10;
int boxH = 60;
epaper.fillRect(boxX, boxY, boxW, boxH, TFT_LIGHTGREY);
epaper.drawRect(boxX, boxY, boxW, boxH, TFT_BLACK);
epaper.setTextColor(TFT_BLACK, TFT_LIGHTGREY);
epaper.setTextDatum(TL_DATUM);
epaper.drawString("IP STA: " + WiFi.localIP().toString(), boxX + 10, boxY + 12, 2);
// --- Pictogramme Wi-Fi centré ---
int iconX = boxX + (boxW/2) - 15;
int iconY = boxY + 5;
drawWiFiIcon(iconX, iconY, WiFi.RSSI());
// --- RSSI sous l’icône ---
epaper.setTextDatum(TC_DATUM);
epaper.drawString("RSSI: " + String(WiFi.RSSI()) + " dBm", boxX + boxW/2, boxY + 40, 2);
epaper.update();
#endif
// --- Sortie série ---
Serial.printf("Heure actuelle : %02d:%02d:%02d\n",
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
Serial.println("IP STA : " + WiFi.localIP().toString());
Serial.println("RSSI : " + String(WiFi.RSSI()) + " dBm");
}
}
// onglet driver.h // driver.h file #define BOARD_SCREEN_COMBO 505 // 1.54 inch monochrome ePaper Screen (SSD1681) #define USE_XIAO_EPAPER_BREAKOUT_BOARD