Guest User

Untitled

a guest
May 2nd, 2026
35
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.63 KB | None | 0 0
  1. #include <WiFi.h>
  2. #include <WiFiUdp.h>
  3. #include <WebServer.h>
  4.  
  5. // --- Configuration Wi-Fi ---
  6. const char* ssid = "WIFI";
  7. const char* password = "PASSWORD";
  8. IPAddress receiverIP(192, 168, 1, 100); // IP de l'autre ESP (ou le vôtre)
  9. const int receiverPort = 1337;
  10. const int localPort = 1337;
  11.  
  12. WiFiUDP udp;
  13. WebServer server(80);
  14.  
  15. // --- Pinout ---
  16. const int boutonMorse = 2; // Bouton physique pour Morse (Point/Trait)
  17. // Pas de bouton physique pour le mode, tout se fait via le Web
  18.  
  19. // --- États du système ---
  20. enum Mode {
  21. MODE_EMETTEUR,
  22. MODE_RECEPTEUR
  23. };
  24.  
  25. Mode systemeMode = MODE_EMETTEUR;
  26.  
  27. // --- Configuration Morse ---
  28. const unsigned long DUREE_POINT = 200;
  29. const unsigned long SEUIL_TRAIT = DUREE_POINT * 1.5;
  30. const unsigned long TEMPS_FIN_LETTRE = 800;
  31.  
  32. unsigned long debutAppui = 0;
  33. unsigned long dernierRelachement = 0;
  34. bool appuiEnCours = false;
  35. String lettreEnCours = "";
  36.  
  37. // --- Buffers ---
  38. String messageRecu = "";
  39. String historiqueRecu = ""; // Pour afficher l'historique sur le web
  40. const int MAX_HISTORIQUE = 50;
  41.  
  42. // --- Fonctions utilitaires ---
  43. void changerModeWeb(Mode nouveauMode) {
  44. systemeMode = nouveauMode;
  45. String msg = (nouveauMode == MODE_EMETTEUR) ? "ÉMISSION" : "RÉCEPTION";
  46. Serial.println(">>> MODE CHANGÉ : " + msg + " <<<");
  47. }
  48.  
  49. // Fonction pour échapper les caractères spéciaux dans un JSON (sans toucher au HTML)
  50. String escapeJson(String str) {
  51. str.replace("\\", "\\\\"); // Échapper les antislashs
  52. str.replace("\"", "\\\""); // Échapper les guillemets (crucial pour le JSON)
  53. str.replace("\n", "\\n"); // Échapper les sauts de ligne
  54. str.replace("\r", "\\r"); // Échapper les retours chariot
  55. str.replace("\t", "\\t"); // Échapper les tabulations
  56. // On NE touche PAS à < et > pour que le HTML reste fonctionnel
  57. return str;
  58. }
  59.  
  60. void setup() {
  61. pinMode(boutonMorse, INPUT_PULLUP);
  62.  
  63. Serial.begin(115200); // Débit plus élevé pour le serial et le web
  64. while (!Serial)
  65. ;
  66.  
  67. Serial.println("=== ESP32 Morse Web ===");
  68.  
  69. // Petit délai pour stabiliser l'alimentation avant le Wi-Fi
  70. delay(1000);
  71.  
  72. Serial.print("Connexion au Wi-Fi...");
  73. WiFi.begin(ssid, password);
  74.  
  75. // Augmentez le délai d'attente pour éviter les redémarrages brutaux
  76. while (WiFi.status() != WL_CONNECTED) {
  77. delay(1000); // Passez de 500ms à 1000ms pour donner plus de temps à l'alimentation
  78. Serial.print(".");
  79. }
  80. Serial.println(" Connecté !");
  81. Serial.print("Adresse IP: ");
  82. Serial.println(WiFi.localIP());
  83.  
  84. // Initialisation UDP
  85. if (udp.begin(localPort)) {
  86. Serial.println("UDP écouteur démarré sur le port " + String(localPort));
  87. } else {
  88. Serial.println("Erreur démarrage UDP");
  89. }
  90.  
  91. // --- Configuration du Serveur Web ---
  92.  
  93. // --- 1. Page d'accueil (HTML + CSS + JS) ---
  94. server.on("/", []() {
  95. String html = "";
  96. String modeTexte = (systemeMode == MODE_EMETTEUR) ? "Passer en Réception" : "Passer en Émission";
  97. String modeClasse = (systemeMode == MODE_EMETTEUR) ? "mode-emetteur" : "mode-recepteur";
  98. String boutonDisabled = (systemeMode == MODE_RECEPTEUR) ? "disabled" : "";
  99. String modeAction = (systemeMode == MODE_EMETTEUR) ? "RECEPTEUR" : "EMETTEUR";
  100.  
  101. html += "<!DOCTYPE html><html><head>";
  102. html += "<title>ESP32 Morse</title>";
  103. html += "<meta name='viewport' content='width=device-width, initial-scale=1.0'>";
  104. html += "<style>";
  105. html += "body { font-family: Arial, sans-serif; text-align: center; padding: 20px; background: #f0f0f0; }";
  106. html += ".container { max-width: 600px; margin: 0 auto; background: white; padding: 20px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }";
  107. html += "h1 { color: #333; }";
  108. html += ".status { font-size: 1.2em; font-weight: bold; margin: 10px 0; padding: 10px; border-radius: 5px; }";
  109. html += ".mode-emetteur { background-color: #d4edda; color: #155724; }";
  110. html += ".mode-recepteur { background-color: #cce5ff; color: #004085; }";
  111. html += ".btn { padding: 15px 30px; font-size: 1.2em; cursor: pointer; border: none; border-radius: 5px; color: white; background: #007bff; transition: 0.3s; }";
  112. html += ".btn:disabled { background: #ccc; cursor: not-allowed; }";
  113. html += ".btn:hover:not(:disabled) { background: #0056b3; }";
  114. html += ".log-box { margin-top: 20px; padding: 10px; border: 1px solid #ddd; border-radius: 5px; background: #fafafa; min-height: 100px; text-align: left; overflow-y: auto; max-height: 200px; }";
  115. html += ".log-entry { margin: 5px 0; padding: 2px; border-bottom: 1px solid #eee; }";
  116. html += ".log-entry.sent { color: green; }";
  117. html += ".log-entry.received { color: blue; }";
  118. html += ".morse-current { font-size: 1.5em; font-weight: bold; color: #333; margin-top: 10px; }";
  119. html += "</style>";html += "</head><body>";
  120.  
  121. html += "<div class='container'>";
  122. html += "<h1>ESP32 Morse</h1>";
  123. html += "<div class='status " + modeClasse + "' id='statusDisplay'>Mode actuel : ...</div>";
  124.  
  125. html += "<button class='btn' onclick='changeMode(\"" + modeAction + "\")'>" + modeTexte + "</button>";
  126.  
  127. html += "<div class='log-box' id='logBox'><strong>Historique :</strong><br></div>";
  128.  
  129. if (systemeMode == MODE_EMETTEUR) {
  130. html += "<div class='morse-current' id='morseDisplay'>Morse en cours : </div>";
  131. }
  132.  
  133. html += "</div>";
  134.  
  135. // Script JS pour le rafraîchissement automatique
  136. html += "<script>";
  137. html += "function changeMode(mode) {";
  138. html += " fetch('/changeMode?m=' + mode);";
  139. html += " location.reload();";
  140. html += "}";
  141. html += "";
  142. html += "function updateUI() {";
  143. html += " fetch('/update')";
  144. html += " .then(response => response.json())";
  145. html += " .then(data => {";
  146. html += " var statusEl = document.getElementById('statusDisplay');";
  147. html += " if(statusEl) {";
  148. html += " var modeText = (data.mode === 'EMETTEUR') ? 'ÉMISSION (Morse)' : 'RÉCEPTION (Écoute)';";
  149. html += " statusEl.innerText = 'Mode actuel : ' + modeText;";
  150. html += " statusEl.className = 'status ' + (data.mode === 'EMETTEUR' ? 'mode-emetteur' : 'mode-recepteur');";
  151. html += " }";
  152. html += "";
  153. html += " var logBox = document.getElementById('logBox');";
  154. html += " if(logBox) {";
  155. html += " var newContent = '<strong>Historique :</strong><br>' + data.history;";
  156. html += "";
  157. html += " if (logBox.innerHTML !== newContent) {";
  158. html += " logBox.innerHTML = newContent;";
  159. html += "";
  160. html += " var isUserAtBottom = (logBox.scrollHeight - logBox.scrollTop) <= (logBox.clientHeight + 10);";
  161. html += "";
  162. html += " if (isUserAtBottom) {";
  163. html += " logBox.scrollTop = logBox.scrollHeight;";
  164. html += " }";
  165. html += " }";
  166. html += " }";
  167. html += "";
  168. html += " var morseEl = document.getElementById('morseDisplay');";
  169. html += " if(morseEl) {";
  170. html += " if (data.mode === 'EMETTEUR') {";
  171. html += " morseEl.innerText = 'Morse en cours : ' + data.currentMorse;";
  172. html += " } else {";
  173. html += " morseEl.innerText = '';";
  174. html += " }";
  175. html += " }";
  176. html += " })";
  177. html += " .catch(err => console.error('Erreur update:', err));";
  178. html += "}";
  179. html += "";
  180. html += "setInterval(updateUI, 500);";
  181. html += "updateUI();";
  182. html += "</script>";
  183.  
  184. server.send(200, "text/html", html);
  185. });
  186.  
  187. // --- 2. Endpoint pour changer le mode ---
  188. server.on("/changeMode", []() {
  189. String mode = server.arg("m");
  190. if (mode == "RECEPTEUR") {
  191. changerModeWeb(MODE_RECEPTEUR);
  192. } else if (mode == "EMETTEUR") {
  193. changerModeWeb(MODE_EMETTEUR);
  194. }
  195. server.send(200, "text/plain", "Mode changé");
  196. });
  197.  
  198. // --- 3. NOUVEL ENDPOINT : Renvoi des données JSON pour le JS ---
  199. server.on("/update", []() {
  200. String modeStr = (systemeMode == MODE_EMETTEUR) ? "EMETTEUR" : "RECEPTEUR";
  201.  
  202. // Échappement CRITIQUE pour éviter de casser le JSON
  203. String historySafe = escapeJson(historiqueRecu);
  204. String morseSafe = escapeJson(lettreEnCours);
  205.  
  206. String json = "{";
  207. json += "\"mode\": \"" + modeStr + "\", ";
  208. json += "\"history\": \"" + historySafe + "\", ";
  209. json += "\"currentMorse\": \"" + morseSafe + "\"";
  210. json += "}";
  211.  
  212. server.send(200, "application/json", json);
  213. });
  214.  
  215. server.begin();
  216. Serial.println("Serveur web démarré sur http://" + WiFi.localIP().toString());
  217. }
  218.  
  219. void loop() {
  220. server.handleClient(); // Gérer les requêtes web
  221.  
  222. // --- 1. Gestion de la réception UDP ---
  223. int packetSize = udp.parsePacket();
  224. if (packetSize > 0) {
  225. char packetBuffer[packetSize + 1];
  226. udp.read(packetBuffer, packetSize);
  227. packetBuffer[packetSize] = 0;
  228.  
  229. String message = String(packetBuffer);
  230. if (message.endsWith("\n")) {
  231. message = message.substring(0, message.length() - 1);
  232. }
  233.  
  234. // Mise à jour de l'historique
  235. String timestamp = String(millis()) + "ms";
  236. String entry = "<div class='log-entry received'>[" + timestamp + "] Reçu: <b>" + message + "</b></div>";
  237.  
  238. if (historiqueRecu.length() > 0) {
  239. historiqueRecu += "<br>" + entry;
  240. } else {
  241. historiqueRecu = entry;
  242. }
  243.  
  244. // Limiter la taille de l'historique
  245. if (historiqueRecu.length() > 2000) {
  246. int lastBr = historiqueRecu.lastIndexOf("<br>");
  247. if (lastBr > 0) historiqueRecu = historiqueRecu.substring(lastBr + 4);
  248. }
  249.  
  250. Serial.print("Reçu: ");
  251. Serial.println(message);
  252. }
  253.  
  254. // --- 2. Gestion selon le mode ---
  255. if (systemeMode == MODE_EMETTEUR) {
  256. gestionEmission();
  257. } else {
  258. // En mode réception, on peut juste attendre, mais on vérifie toujours les paquets
  259. // Le code de réception est déjà géré au début de la boucle
  260. delay(10);
  261. }
  262. }
  263.  
  264. void gestionEmission() {
  265. int etatBouton = digitalRead(boutonMorse);
  266. unsigned long tempsActuel = millis();
  267.  
  268. // Détection du début d'appui
  269. if (etatBouton == LOW && !appuiEnCours) {
  270. // Petit délai de stabilisation pour éviter les faux appuis (debouncing)
  271. delay(50);
  272. // Vérification à nouveau après le délai
  273. if (digitalRead(boutonMorse) == LOW) {
  274. appuiEnCours = true;
  275. debutAppui = tempsActuel;
  276. }
  277. }
  278.  
  279. if (etatBouton == HIGH && appuiEnCours) {
  280. appuiEnCours = false;
  281. dernierRelachement = tempsActuel;
  282.  
  283. unsigned long duree = tempsActuel - debutAppui;
  284.  
  285. // Augmenter légèrement le seuil pour le trait si nécessaire,
  286. // mais surtout éviter la détection immédiate après un relâchement
  287. if (duree < SEUIL_TRAIT) {
  288. lettreEnCours += ".";
  289. } else {
  290. lettreEnCours += "-";
  291. }
  292. }
  293.  
  294. // Logique de fin de lettre inchangée
  295. if (lettreEnCours.length() > 0 && !appuiEnCours) {
  296. if (tempsActuel - dernierRelachement > TEMPS_FIN_LETTRE) {
  297. traduireEtEnvoyer();
  298. dernierRelachement = tempsActuel;
  299. }
  300. }
  301. }
  302.  
  303. void traduireEtEnvoyer() {
  304. String code = lettreEnCours;
  305. String caractere = "";
  306.  
  307. // Traduction Morse
  308. if (code == ".-") caractere = "A";
  309. else if (code == "-...") caractere = "B";
  310. else if (code == "-.-.") caractere = "C";
  311. else if (code == "-..") caractere = "D";
  312. else if (code == ".") caractere = "E";
  313. else if (code == "..-.") caractere = "F";
  314. else if (code == "--.") caractere = "G";
  315. else if (code == "....") caractere = "H";
  316. else if (code == "..") caractere = "I";
  317. else if (code == ".---") caractere = "J";
  318. else if (code == "-.-") caractere = "K";
  319. else if (code == ".-..") caractere = "L";
  320. else if (code == "--") caractere = "M";
  321. else if (code == "-.") caractere = "N";
  322. else if (code == "---") caractere = "O";
  323. else if (code == ".--.") caractere = "P";
  324. else if (code == "--.-") caractere = "Q";
  325. else if (code == ".-.") caractere = "R";
  326. else if (code == "...") caractere = "S";
  327. else if (code == "-") caractere = "T";
  328. else if (code == "..-") caractere = "U";
  329. else if (code == "...-") caractere = "V";
  330. else if (code == ".--") caractere = "W";
  331. else if (code == "-..-") caractere = "X";
  332. else if (code == "-.--") caractere = "Y";
  333. else if (code == "--..") caractere = "Z";
  334.  
  335. else if (code == ".----") caractere = "1";
  336. else if (code == "..---") caractere = "2";
  337. else if (code == "...--") caractere = "3";
  338. else if (code == "....-") caractere = "4";
  339. else if (code == ".....") caractere = "5";
  340. else if (code == "-....") caractere = "6";
  341. else if (code == "--...") caractere = "7";
  342. else if (code == "---..") caractere = "8";
  343. else if (code == "----.") caractere = "9";
  344. else if (code == "-----") caractere = "0";
  345.  
  346. if (caractere != "") {
  347. Serial.print("Envoi: ");
  348. Serial.println(caractere);
  349. envoyerLettre(caractere);
  350.  
  351. // Ajouter à l'historique local
  352. String timestamp = String(millis()) + "ms";
  353. String entry = "<div class='log-entry sent'>[" + timestamp + "] Envoyé: <b>" + caractere + "</b></div>";
  354. if (historiqueRecu.length() > 0) {
  355. historiqueRecu += "<br>" + entry;
  356. } else {
  357. historiqueRecu = entry;
  358. }
  359. if (historiqueRecu.length() > 2000) {
  360. int lastBr = historiqueRecu.lastIndexOf("<br>");
  361. if (lastBr > 0) historiqueRecu = historiqueRecu.substring(lastBr + 4);
  362. }
  363. } else {
  364. Serial.print("Code inconnu: ");
  365. Serial.println(code);
  366. }
  367. lettreEnCours = "";
  368. }
  369.  
  370. void envoyerLettre(String lettre) {
  371. String message = lettre + "\n";
  372. udp.beginPacket(receiverIP, receiverPort);
  373. udp.print(message);
  374. udp.endPacket();
  375. Serial.println("Paquet envoyé.");
  376. }
Advertisement
Add Comment
Please, Sign In to add comment