Arduino Nano ESP32 - Traceur Web

Ce tutoriel vous explique comment construire un traceur web qui ressemble au Traceur Série trouvé dans l'IDE Arduino. Ce traceur web permet de surveiller les données en temps réel provenant d'un Arduino Nano ESP32 à l'aide d'un navigateur web sur votre smartphone ou PC. Les données tracées seront présentées sous forme de graphique, semblables à ce que vous observez habituellement dans le Traceur Série de l'IDE Arduino.

Traceur Web Arduino Nano ESP32

Préparation du matériel

1×Arduino Nano ESP32
1×USB Cable Type-C
1×(Recommended) Screw Terminal Adapter for Arduino Nano

Or you can buy the following sensor kits:

1×DIYables Sensor Kit (30 sensors/displays)
1×DIYables Sensor Kit (18 sensors/displays)
Divulgation : Certains des liens fournis dans cette section sont des liens affiliés Amazon. Nous pouvons recevoir une commission pour tout achat effectué via ces liens, sans coût supplémentaire pour vous. Nous vous remercions de votre soutien.

Comment fonctionne le traceur web

  • Le code Arduino Nano ESP32 crée à la fois un serveur web et un serveur WebSocket.
  • Lorsqu'un utilisateur accède à la page web hébergée sur la carte Arduino Nano ESP32 via un navigateur web, le serveur web de l'Arduino Nano ESP32 renvoie le contenu web (HTML, CSS, JavaScript) au navigateur.
  • Le code JavaScript exécuté dans le navigateur web crée un graphique semblable au Traceur Série.
  • En cliquant sur le bouton de connexion sur la page web, le code JavaScript initie une connexion WebSocket au serveur WebSocket fonctionnant sur la carte Arduino Nano ESP32.
  • L'Arduino Nano ESP32 envoie des données via la connexion WebSocket au navigateur web dans un format similaire à celui utilisé par le Traceur Série (détails fournis dans la partie suivante).
  • Le code JavaScript dans le navigateur web reçoit les données et les trace sur le graphique.

Le format de données que l'Arduino Nano ESP32 envoie au traceur web

Pour tracer plusieurs variables, nous devons séparer les variables les unes des autres par le caractère « \t » ou «  ». La dernière valeur DOIT être terminée par les caractères « \r\n ».

En détail :

  • La première variable
plotter.broadcastTXT(data_1);
  • Les variables du milieu
plotter.broadcastTXT("\t"); // Un caractère de tabulation ('\t') ou un espace (' ') est imprimé entre les deux valeurs. plotter.broadcastTXT(data_2); plotter.broadcastTXT("\t"); // Un caractère de tabulation ('\t') ou un espace (' ') est imprimé entre les deux valeurs. plotter.broadcastTXT(data_3);
  • La dernière variable
plotter.broadcastTXT("\t"); // Un caractère de tabulation ('\t') ou un espace (' ') est imprimé entre les deux valeurs. plotter.broadcastTXT(data_4); plotter.broadcastTXT("\r\n"); // La dernière valeur est terminée par un retour chariot ('\r') et un caractère de nouvelle ligne ('\n').

Pour plus de détails, veuillez consulter le tutoriel Arduino Nano ESP32 - Traceur Série.

Code Arduino Nano ESP32 - Traceur Web

Le contenu de la page web (HTML, CSS, JavaScript) est stocké séparément dans un fichier index.h. Par conséquent, dans l'IDE Arduino, nous aurons deux fichiers de code :

  • Un fichier .ino contenant le code Arduino Nano ESP32, qui crée à la fois un serveur web et un serveur WebSocket.
  • Un fichier .h qui contient le contenu de la page web.

Étapes rapides

Pour commencer avec Arduino Nano ESP32, suivez ces étapes :

  • Si vous êtes nouveau sur Arduino Nano ESP32, consultez le tutoriel sur comment configurer l'environnement pour Arduino Nano ESP32 dans l'Arduino IDE.
  • Connectez la carte Arduino Nano ESP32 à votre PC via un câble USB.
  • Ouvrez l'Arduino IDE sur votre PC.
  • Sélectionnez la bonne carte Arduino Nano ESP32 (par exemple, Arduino Nano ESP32) et le port COM.
  • Ouvrez le gestionnaire de bibliothèques en cliquant sur l'icône Gestionnaire de bibliothèques dans la barre de navigation gauche de l'Arduino IDE.
  • Recherchez “ESPAsyncWebServer”, puis trouvez ESPAsyncWebServer créé par lacamera.
  • Cliquez sur le bouton Install pour installer la bibliothèque ESPAsyncWebServer.
Bibliothèque ESPAsyncWebServer pour Arduino Nano ESP32
  • On vous demandera d'installer la dépendance. Cliquez sur le bouton Install All.
Bibliothèque de dépendances ESPAsyncWebServer pour Arduino Nano ESP32
  • Recherchez « WebSockets », puis trouvez les WebSockets créés par Markus Sattler.
  • Cliquez sur le bouton Install pour installer la bibliothèque WebSockets.
Bibliothèque WebSockets pour Arduino Nano ESP32
  • Dans l'IDE Arduino, créez un nouveau sketch, nommez-le, par exemple, newbiely.fr.ino
  • Copiez le code ci-dessous et ouvrez-le avec l'IDE Arduino
/* * Ce code Arduino Nano ESP32 a été développé par newbiely.fr * Ce code Arduino Nano ESP32 est mis à disposition du public sans aucune restriction. * Pour des instructions complètes et des schémas de câblage, veuillez visiter: * https://newbiely.fr/tutorials/arduino-nano-esp32/arduino-nano-esp32-web-plotter */ #include <WiFi.h> #include <ESPAsyncWebServer.h> #include <WebSocketsServer.h> #include "index.h" // contains HTML, JavaScript and CSS const char* ssid = "YOUR_WIFI_SSID"; // REPLACE IT WITH YOUR OWN NETWORK CREDENTIALS const char* password = "YOUR_WIFI_PASSWORD"; // REPLACE IT WITH YOUR OWN NETWORK CREDENTIALS AsyncWebServer server(80); WebSocketsServer plotter = WebSocketsServer(81); // WebSocket server on port 81 int last_update = 0; void setup() { Serial.begin(9600); delay(1000); // Connect to Wi-Fi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi..."); } Serial.println("Connected to WiFi"); // Initialize WebSocket server plotter.begin(); // Serve a basic HTML page with JavaScript to create the WebSocket connection server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) { Serial.println("Web Server: received a web page request"); String html = HTML_CONTENT; // Use the HTML content from the index.h file request->send(200, "text/html", html); }); server.begin(); Serial.print("Arduino Nano ESP32 Web Server's IP address: "); Serial.println(WiFi.localIP()); } void loop() { plotter.loop(); if (millis() - last_update > 500) { last_update = millis(); String data_1 = String(random(0, 100)); String data_2 = String(random(0, 100)); String data_3 = String(random(0, 100)); String data_4 = String(random(0, 100)); // TO SERIAL PLOTTER Serial.print(data_1); Serial.print("\t"); // A tab character ('\t') or a space (' ') is printed between the two values. Serial.print(data_2); Serial.print("\t"); // A tab character ('\t') or a space (' ') is printed between the two values. Serial.print(data_3); Serial.print("\t"); // A tab character ('\t') or a space (' ') is printed between the two values. Serial.println(data_4); // The last value is terminated by a carriage return ('\r') and a newline ('\n') character. // TO WEB PLOTTER plotter.broadcastTXT(data_1); plotter.broadcastTXT("\t"); // A tab character ('\t') or a space (' ') is printed between the two values. plotter.broadcastTXT(data_2); plotter.broadcastTXT("\t"); // A tab character ('\t') or a space (' ') is printed between the two values. plotter.broadcastTXT(data_3); plotter.broadcastTXT("\t"); // A tab character ('\t') or a space (' ') is printed between the two values. plotter.broadcastTXT(data_4); plotter.broadcastTXT("\r\n"); // The last value is terminated by a carriage return ('\r') and a newline ('\n') character. } }
  • Modifiez les informations WiFi (SSID et mot de passe) dans le code pour qu'elles correspondent à vos propres identifiants réseau.
  • Créez le fichier index.h dans l'IDE Arduino en :
    • Cliquant soit sur le bouton juste en dessous de l'icône du moniteur série et choisissez Nouvel Onglet, soit en utilisant les touches Ctrl+Maj+N.
    Arduino IDE 2 ajoute un fichier
    • Nommez le fichier index.h et cliquez sur le bouton OK
    Arduino IDE 2 ajoute le fichier index.h.
    • Copiez le code ci-dessous et collez-le dans index.h.
    /* * Ce code Arduino Nano ESP32 a été développé par newbiely.fr * Ce code Arduino Nano ESP32 est mis à disposition du public sans aucune restriction. * Pour des instructions complètes et des schémas de câblage, veuillez visiter: * https://newbiely.fr/tutorials/arduino-nano-esp32/arduino-nano-esp32-web-plotter */ const char *HTML_CONTENT = R"=====( <!DOCTYPE html> <html> <head> <title>Arduino Nano ESP32 - Web Plotter</title> <meta name="viewport" content="width=device-width, initial-scale=0.7"> <style> body {text-align: center; height: 750px; } h1 {font-weight: bold; font-size: 20pt; padding-bottom: 5px; color: navy; } h2 {font-weight: bold; font-size: 15pt; padding-bottom: 5px; } button {font-weight: bold; font-size: 15pt; } #footer {width: 100%; margin: 0px; padding: 0px 0px 10px 0px; bottom: 0px; } .sub-footer {margin: 0 auto; position: relative; width:400px; } .sub-footer a {position: absolute; font-size: 10pt; top: 3px; } </style> <script> var COLOR_BACKGROUND = "#FFFFFF"; var COLOR_TEXT = "#000000"; var COLOR_BOUND = "#000000"; var COLOR_GRIDLINE = "#F0F0F0"; var COLOR_LINE = ["#0000FF", "#FF0000", "#009900", "#FF9900", "#CC00CC", "#666666", "#00CCFF", "#000000"]; var LEGEND_WIDTH = 10; var X_TITLE_HEIGHT = 40; var Y_TITLE_WIDTH = 40; var X_VALUE_HEIGHT = 40; var Y_VALUE_WIDTH = 50; var PLOTTER_PADDING_TOP = 30; var PLOTTER_PADDING_RIGHT = 30; var X_GRIDLINE_NUM = 5; var Y_GRIDLINE_NUM = 4; var WSP_WIDTH = 400; var WSP_HEIGHT = 200; var MAX_SAMPLE = 50; // in sample var X_MIN = 0; var X_MAX = MAX_SAMPLE; var Y_MIN = -5; var Y_MAX = 5; var X_TITLE = "X"; var Y_TITLE = "Y"; var plotter_width; var plotter_height; var plotter_pivot_x; var plotter_pivot_y; var sample_count = 0; var buffer = ""; var data = []; var webSocket; var canvas; var ctx; function init(){ canvas = document.getElementById("graph"); canvas.style.backgroundColor = COLOR_BACKGROUND; ctx = canvas.getContext("2d"); canvas_resize(); setInterval(update_plotter, 1000 / 60); } function connect_to_esp32(){ if(webSocket == null){ webSocket = new WebSocket("ws://" + window.location.host + ":81"); document.getElementById("ws_state").innerHTML = "CONNECTING"; webSocket.onopen = ws_onopen; webSocket.onclose = ws_onclose; webSocket.onmessage = ws_onmessage; webSocket.binaryType = "arraybuffer"; } else webSocket.close(); } function ws_onopen(){ document.getElementById("ws_state").innerHTML = "<span style='color: blue'>CONNECTED</span>"; document.getElementById("btn_connect").innerHTML = "Disconnect"; } function ws_onclose(){ document.getElementById("ws_state").innerHTML = "<span style='color: gray'>CLOSED</span>"; document.getElementById("btn_connect").innerHTML = "Connect"; webSocket.onopen = null; webSocket.onclose = null; webSocket.onmessage = null; webSocket = null; } function ws_onmessage(e_msg){ e_msg = e_msg || window.event; // MessageEvent console.log(e_msg.data); buffer += e_msg.data; buffer = buffer.replace(/\r\n/g, "\n"); buffer = buffer.replace(/\r/g, "\n"); while(buffer.indexOf("\n") == 0) buffer = buffer.substr(1); if(buffer.indexOf("\n") <= 0) return; var pos = buffer.lastIndexOf("\n"); var str = buffer.substr(0, pos); var new_sample_arr = str.split("\n"); buffer = buffer.substr(pos + 1); for(var si = 0; si < new_sample_arr.length; si++) { var str = new_sample_arr[si]; var arr = []; if(str.indexOf("\t") > 0) arr = str.split("\t"); else arr = str.split(" "); for(var i = 0; i < arr.length; i++){ var value = parseFloat(arr[i]); if(isNaN(value)) continue; if(i >= data.length) { var new_line = [value]; data.push(new_line); // new line } else data[i].push(value); } sample_count++; } for(var line = 0; line < data.length; line++){ while(data[line].length > MAX_SAMPLE) data[line].splice(0, 1); } auto_scale(); } function map(x, in_min, in_max, out_min, out_max){ return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } function get_random_color(){ var letters = '0123456789ABCDEF'; var _color = '#'; for (var i = 0; i < 6; i++) _color += letters[Math.floor(Math.random() * 16)]; return _color; } function update_plotter(){ if(sample_count <= MAX_SAMPLE) X_MAX = sample_count; else X_MAX = 50; ctx.clearRect(0, 0, WSP_WIDTH, WSP_HEIGHT); ctx.save(); ctx.translate(plotter_pivot_x, plotter_pivot_y); ctx.font = "bold 20px Arial"; ctx.textBaseline = "middle"; ctx.textAlign = "center"; ctx.fillStyle = COLOR_TEXT; // draw X axis title if(X_TITLE != "") ctx.fillText(X_TITLE, plotter_width / 2, X_VALUE_HEIGHT + X_TITLE_HEIGHT / 2); // draw Y axis title if(Y_TITLE != ""){ ctx.rotate(-90 * Math.PI / 180); ctx.fillText(Y_TITLE, plotter_height / 2, -Y_VALUE_WIDTH - Y_TITLE_WIDTH / 2); ctx.rotate(90 * Math.PI / 180); } ctx.font = "16px Arial"; ctx.textAlign = "right"; ctx.strokeStyle = COLOR_BOUND; for(var i = 0; i <= Y_GRIDLINE_NUM; i++){ var y_gridline_px = -map(i, 0, Y_GRIDLINE_NUM, 0, plotter_height); y_gridline_px = Math.round(y_gridline_px) + 0.5; ctx.beginPath(); ctx.moveTo(0, y_gridline_px); ctx.lineTo(plotter_width, y_gridline_px); ctx.stroke(); ctx.strokeStyle = COLOR_BOUND; ctx.beginPath(); ctx.moveTo(-7 , y_gridline_px); ctx.lineTo(4, y_gridline_px); ctx.stroke(); var y_gridline_value = map(i, 0, Y_GRIDLINE_NUM, Y_MIN, Y_MAX); y_gridline_value = y_gridline_value.toFixed(1); ctx.fillText(y_gridline_value + "", -15, y_gridline_px); ctx.strokeStyle = COLOR_GRIDLINE; } ctx.strokeStyle = COLOR_BOUND; ctx.textAlign = "center"; ctx.beginPath(); ctx.moveTo(0.5, y_gridline_px - 7); ctx.lineTo(0.5, y_gridline_px + 4); ctx.stroke(); for(var i = 0; i <= X_GRIDLINE_NUM; i++){ var x_gridline_px = map(i, 0, X_GRIDLINE_NUM, 0, plotter_width); x_gridline_px = Math.round(x_gridline_px) + 0.5; ctx.beginPath(); ctx.moveTo(x_gridline_px, 0); ctx.lineTo(x_gridline_px, -plotter_height); ctx.stroke(); ctx.strokeStyle = COLOR_BOUND; ctx.beginPath(); ctx.moveTo(x_gridline_px, 7); ctx.lineTo(x_gridline_px, -4); ctx.stroke(); var x_gridline_value; if(sample_count <= MAX_SAMPLE) x_gridline_value = map(i, 0, X_GRIDLINE_NUM, X_MIN, X_MAX); else x_gridline_value = map(i, 0, X_GRIDLINE_NUM, sample_count - MAX_SAMPLE, sample_count);; ctx.fillText(x_gridline_value.toString(), x_gridline_px, X_VALUE_HEIGHT / 2 + 5); ctx.strokeStyle = COLOR_GRIDLINE; } var line_num = data.length; for(var line = 0; line < line_num; line++){ // draw graph var sample_num = data[line].length; if(sample_num >= 2){ var y_value = data[line][0]; var x_px = 0; var y_px = -map(y_value, Y_MIN, Y_MAX, 0, plotter_height); if(line == COLOR_LINE.length) COLOR_LINE.push(get_random_color()); ctx.strokeStyle = COLOR_LINE[line]; ctx.beginPath(); ctx.moveTo(x_px, y_px); for(var i = 0; i < sample_num; i++){ y_value = data[line][i]; x_px = map(i, X_MIN, X_MAX -1, 0, plotter_width); y_px = -map(y_value, Y_MIN, Y_MAX, 0, plotter_height); ctx.lineTo(x_px, y_px); } ctx.stroke(); } // draw legend var x = plotter_width - (line_num - line) * LEGEND_WIDTH - (line_num - line - 1) * LEGEND_WIDTH / 2; var y = -plotter_height - PLOTTER_PADDING_TOP / 2 - LEGEND_WIDTH / 2; ctx.fillStyle = COLOR_LINE[line]; ctx.beginPath(); ctx.rect(x, y, LEGEND_WIDTH, LEGEND_WIDTH); ctx.fill(); } ctx.restore(); } function canvas_resize(){ canvas.width = 0; // to avoid wrong screen size canvas.height = 0; document.getElementById('footer').style.position = "fixed"; var width = window.innerWidth - 20; var height = window.innerHeight - 20; WSP_WIDTH = width; WSP_HEIGHT = height - document.getElementById('header').offsetHeight - document.getElementById('footer').offsetHeight; canvas.width = WSP_WIDTH; canvas.height = WSP_HEIGHT; ctx.font = "16px Arial"; var y_min_text_size = ctx.measureText(Y_MIN.toFixed(1) + "").width; var y_max_text_size = ctx.measureText(Y_MAX.toFixed(1) + "").width; Y_VALUE_WIDTH = Math.round(Math.max(y_min_text_size, y_max_text_size)) + 15; plotter_width = WSP_WIDTH - Y_VALUE_WIDTH - PLOTTER_PADDING_RIGHT; plotter_height = WSP_HEIGHT - X_VALUE_HEIGHT - PLOTTER_PADDING_TOP; plotter_pivot_x = Y_VALUE_WIDTH; plotter_pivot_y = WSP_HEIGHT - X_VALUE_HEIGHT; if(X_TITLE != "") { plotter_height -= X_TITLE_HEIGHT; plotter_pivot_y -= X_TITLE_HEIGHT; } if(Y_TITLE != "") { plotter_width -= Y_TITLE_WIDTH; plotter_pivot_x += Y_TITLE_WIDTH; } ctx.lineWidth = 1; } function auto_scale(){ if(data.length >= 1){ var max_arr = []; var min_arr = []; for(var i = 0; i < data.length; i++){ if(data[i].length >= 1){ var max = Math.max.apply(null, data[i]); var min = Math.min.apply(null, data[i]); max_arr.push(max); min_arr.push(min); } } var max = Math.max.apply(null, max_arr); var min = Math.min.apply(null, min_arr); var MIN_DELTA = 10.0; if((max - min) < MIN_DELTA){ var mid = (max + min) / 2; max = mid + MIN_DELTA / 2; min = mid - MIN_DELTA / 2; } var range = max - min; var exp; if (range == 0.0) exp = 0; else exp = Math.floor(Math.log10(range / 4)); var scale = Math.pow(10, exp); var raw_step = (range / 4) / scale; var step; potential_steps =[1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.0, 8.0, 10.0]; for (var i = 0; i < potential_steps.length; i++) { if (potential_steps[i] < raw_step) continue; step = potential_steps[i] * scale; Y_MIN = step * Math.floor(min / step); Y_MAX = Y_MIN + step * (4); if (Y_MAX >= max) break; } var count = 5 - Math.floor((Y_MAX - max) / step); Y_MAX = Y_MIN + step * (count - 1); ctx.font = "16px Arial"; var y_min_text_size = ctx.measureText(Y_MIN.toFixed(1) + "").width; var y_max_text_size = ctx.measureText(Y_MAX.toFixed(1) + "").width; Y_VALUE_WIDTH = Math.round(Math.max(y_min_text_size, y_max_text_size)) + 15; plotter_width = WSP_WIDTH - Y_VALUE_WIDTH - PLOTTER_PADDING_RIGHT; plotter_pivot_x = Y_VALUE_WIDTH; } } window.onload = init; </script> </head> <body onresize="canvas_resize()"> <h1 id="header">Arduino Nano ESP32 - Web Plotter</h1> <canvas id="graph"></canvas> <br> <div id="footer"> <div class="sub-footer"> <h2>WebSocket <span id="ws_state"><span style="color: gray">CLOSED</span></span></h2> </div> <button id="btn_connect" type="button" onclick="connect_to_esp32();">Connect</button> </div> </body> </html> )=====";
    • Maintenant, vous avez le code dans deux fichiers : newbiely.fr.ino et index.h
    • Cliquez sur le bouton Upload dans l'IDE Arduino pour téléverser le code sur l'Arduino Nano ESP32.
    • Ouvrez le moniteur série
    • Vérifiez le résultat sur le moniteur série.
    COM6
    Send
    Connecting to WiFi... Connected to WiFi Arduino Nano ESP32 Web Server's IP address IP address: 192.168.0.6
    Autoscroll Show timestamp
    Clear output
    9600 baud  
    Newline  
    • Prenez note de l'adresse IP affichée et saisissez cette adresse dans la barre d'adresse d'un navigateur web sur votre smartphone ou PC.
    • Vous verrez la page web comme ci-dessous :
    Navigateur Web pour traceur Arduino Nano ESP32
    • Cliquez sur le bouton CONNECT pour connecter la page web à l'Arduino Nano ESP32 via WebSocket.
    • Vous verrez le traceur tracer des données comme sur l'image ci-dessous.
    Graphique web Arduino Nano ESP32
    • Vous pouvez ouvrir le traceur série dans l'IDE Arduino pour le comparer avec le traceur Web dans le navigateur Web.

    ※ NOTE THAT:

    • Si vous modifiez le contenu HTML dans le fichier index.h et que vous ne faites aucune modification dans le fichier newbiely.fr.ino, lorsque vous compilez et téléchargez le code sur l'Arduino Nano ESP32 en utilisant l'Arduino IDE, l'IDE ne mettra pas à jour le contenu HTML.
    • Pour forcer l'Arduino IDE à mettre à jour le contenu HTML dans ce scénario, vous devez effectuer un changement dans le fichier newbiely.fr.ino. Par exemple, vous pouvez ajouter une ligne vide ou inclure un commentaire.

    Explication du code ligne par ligne

    Le code Arduino Nano ESP32 ci-dessus contient des explications ligne par ligne. Veuillez lire les commentaires dans le code !

※ OUR MESSAGES

  • Please feel free to share the link of this tutorial. However, Please do not use our content on any other websites. We invested a lot of effort and time to create the content, please respect our work!