ESP8266 - Webplotter

Dieses Tutorial zeigt Ihnen, wie Sie einen webbasierten Plotter erstellen, der dem Serial Plotter ähnelt, der in der Arduino-IDE zu finden ist. Diese Einrichtung ermöglicht es Ihnen, Echtzeitdaten eines ESP8266 bequem über einen Webbrowser auf Ihrem Smartphone oder PC zu überwachen. Es visualisiert die Daten in einem grafischen Format, das dem entspricht, was Sie im Serial Plotter der Arduino-IDE beobachten.

ESP8266 NodeMCU Webplotter

Erforderliche Hardware

1×ESP8266 NodeMCU
1×USB-Kabel Typ-A zu Typ-C (für USB-A PC)
1×USB-Kabel Typ-C zu Typ-C (für USB-C PC)
1×(Empfohlen) Schraubklemmen-Erweiterungsboard für ESP8266
1×(Empfohlen) Stromverteiler für ESP8266 Typ-C

Oder Sie können die folgenden Kits kaufen:

1×DIYables Sensor-Kit (30 Sensoren/Displays)
1×DIYables Sensor-Kit (18 Sensoren/Displays)
Offenlegung: Einige der in diesem Abschnitt bereitgestellten Links sind Amazon-Affiliate-Links. Wir können eine Provision für Käufe erhalten, die über diese Links getätigt werden, ohne zusätzliche Kosten für Sie. Wir schätzen Ihre Unterstützung.

Wie der Web Plotter funktioniert

  • Der ESP8266-Code erstellt sowohl einen Webserver als auch einen WebSocket-Server.
  • Wenn ein Benutzer die auf dem ESP8266-Board gehostete Webseite über einen Webbrowser aufruft, sendet der Webserver des ESP8266 den Webinhalt (HTML, CSS, JavaScript) an den Browser zurück.
  • Der JavaScript-Code, der im Webbrowser läuft, zeichnet ein Diagramm, das dem seriellen Plotter ähnelt.
  • Beim Klicken auf den Connect-Button auf der Webseite wird eine WebSocket-Verbindung zum WebSocket-Server hergestellt, der auf dem ESP8266-Board läuft.
  • Der ESP8266 sendet Daten über die WebSocket-Verbindung an den Webbrowser in einem Format, das dem des seriellen Plotters ähnelt (Details dazu im nächsten Abschnitt).
  • Der JavaScript-Code im Webbrowser empfängt die Daten und zeichnet sie im Diagramm.

Das Datenformat, das der ESP8266 an den Web-Plotter sendet

Um mehrere Variablen zu plotten, müssen wir Variablen voneinander durch das Zeichen “\t” oder das Zeichen " " voneinander trennen. Der letzte Wert muss durch das Zeichen “\r\n” beendet werden.

Im Detail:

  • Die erste Variable
plotter.broadcastTXT(line_1);
  • Die mittleren Variablen
plotter.broadcastTXT("\t"); // Ein Tabulator-Zeichen '\t' oder ein Leerzeichen ' ' wird zwischen den beiden Werten ausgegeben. plotter.broadcastTXT(line_2); plotter.broadcastTXT("\t"); // Ein Tabulator-Zeichen '\t' oder ein Leerzeichen ' ' wird zwischen den beiden Werten ausgegeben. plotter.broadcastTXT(line_3);
  • Die letzte Variable
plotter.broadcastTXT("\t"); // Ein Tabulatorzeichen '\t' oder ein Leerzeichen ' ' wird zwischen den beiden Werten ausgegeben. plotter.broadcastTXT(line_4); plotter.broadcastTXT("\r\n"); // Der letzte Wert wird durch einen Wagenrücklauf und einen Zeilenumbruch beendet.

Für weitere Details lesen Sie bitte das Tutorial ESP8266 - Serial Plotter.

ESP8266-Code - Web-Plotter

Der Inhalt der Webseite (HTML, CSS, JavaScript) wird separat in einer index.h-Datei gespeichert. So werden wir zwei Code-Dateien in der Arduino-IDE haben:

  • Eine .ino-Datei mit ESP8266-Code, die einen Webserver und einen WebSocket-Server erstellt.
  • Eine .h-Datei, die den Inhalt der Webseite enthält.

Schnelle Schritte

Um mit ESP8266 in der Arduino-IDE zu beginnen, folgen Sie diesen Schritten:

  • Schauen Sie sich das how to setup environment for ESP8266 on Arduino IDE Tutorial an, falls dies Ihre erste Verwendung von ESP8266 ist.
  • Verbinden Sie das ESP8266-Board mit Ihrem Computer über ein USB-Kabel.
  • Öffnen Sie die Arduino IDE auf Ihrem Computer.
  • Wählen Sie das richtige ESP8266-Board, z. B. NodeMCU 1.0 (ESP-12E Modul), und den jeweiligen COM-Port.
  • Öffnen Sie den Bibliotheks-Manager, indem Sie auf das Symbol Bibliotheks-Manager in der linken Navigationsleiste der Arduino IDE klicken.
  • Suchen Sie „WebSockets“, und finden Sie die von Markus Sattler erstellten WebSockets.
  • Klicken Sie auf die Schaltfläche Installieren, um die WebSockets-Bibliothek zu installieren.
ESP8266 NodeMCU WebSockets-Bibliothek
  • Im Arduino IDE erstelle einen neuen Sketch, gib ihm einen Namen, zum Beispiel newbiely.com.ino
  • Kopiere den untenstehenden Code und öffne ihn mit der Arduino IDE
/* * Dieser ESP8266 NodeMCU Code wurde von newbiely.de entwickelt * Dieser ESP8266 NodeMCU Code wird der Öffentlichkeit ohne jegliche Einschränkung zur Verfügung gestellt. * Für vollständige Anleitungen und Schaltpläne besuchen Sie bitte: * https://newbiely.de/tutorials/esp8266/esp8266-web-plotter */ #include <ESP8266WiFi.h> #include <ESP8266WebServer.h> #include <WebSocketsServer.h> #include "index.h" // contains HTML, JavaScript and CSS const char* ssid = "YOUR_WIFI_SSID"; // CHANGE IT TO MATCH YOUR OWN NETWORK CREDENTIALS const char* password = "YOUR_WIFI_PASSWORD"; // CHANGE IT TO MATCH YOUR OWN NETWORK CREDENTIALS ESP8266WebServer server(80); // Web server on port 80 WebSocketsServer plotter = WebSocketsServer(81); // WebSocket server on port 81 int last_update = 0; void setup() { Serial.begin(9600); delay(500); // 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, []() { Serial.println("Web Server: received a web page request"); String html = HTML_CONTENT; // Use the HTML content from the index.h file server.send(200, "text/html", html); }); server.begin(); Serial.print("ESP8266 Web Server's IP address: "); Serial.println(WiFi.localIP()); } void loop() { // Handle client requests server.handleClient(); // Handle WebSocket events plotter.loop(); if (millis() - last_update > 500) { last_update = millis(); String line_1 = String(random(0, 100)); String line_2 = String(random(0, 100)); String line_3 = String(random(0, 100)); String line_4 = String(random(0, 100)); // TO SERIAL PLOTTER Serial.print(line_1); Serial.print("\t"); // A tab character ('\t') or a space (' ') is printed between the two values. Serial.print(line_2); Serial.print("\t"); // A tab character ('\t') or a space (' ') is printed between the two values. Serial.print(line_3); Serial.print("\t"); // A tab character ('\t') or a space (' ') is printed between the two values. Serial.println(line_4); // The last value is terminated by a carriage return ('\r') and a newline ('\n') character. // TO WEB PLOTTER plotter.broadcastTXT(line_1); plotter.broadcastTXT("\t"); // A tab character ('\t') or a space (' ') is printed between the two values. plotter.broadcastTXT(line_2); plotter.broadcastTXT("\t"); // A tab character ('\t') or a space (' ') is printed between the two values. plotter.broadcastTXT(line_3); plotter.broadcastTXT("\t"); // A tab character ('\t') or a space (' ') is printed between the two values. plotter.broadcastTXT(line_4); plotter.broadcastTXT("\r\n"); // The last value is terminated by a carriage return ('\r') and a newline ('\n') character. } }
  • Passen Sie die WiFi-Informationen (SSID und Passwort) im Code an, damit sie mit Ihren eigenen Netzwerkanmeldeinformationen übereinstimmen.
  • Erstellen Sie die Datei index.h in der Arduino-IDE durch:
    • Entweder klicken Sie auf die Schaltfläche direkt unter dem Seriemonitor-Symbol und wählen Sie Neue Registerkarte, oder verwenden Sie die Tasten Ctrl+Shift+N.
    Arduino IDE 2 fügt eine Datei hinzu.
    • Geben Sie den Dateinamen index.h ein und klicken Sie auf die OK Schaltfläche
    Arduino IDE 2 fügt die Datei index.h hinzu.
    • Kopieren Sie den untenstehenden Code und fügen Sie ihn in die index.h ein.
    /* * Dieser ESP8266 NodeMCU Code wurde von newbiely.de entwickelt * Dieser ESP8266 NodeMCU Code wird der Öffentlichkeit ohne jegliche Einschränkung zur Verfügung gestellt. * Für vollständige Anleitungen und Schaltpläne besuchen Sie bitte: * https://newbiely.de/tutorials/esp8266/esp8266-web-plotter */ const char *HTML_CONTENT = R"=====( <!DOCTYPE html> <html> <head> <title>ESP8266 - 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 plotter_init(){ canvas = document.getElementById("graph"); canvas.style.backgroundColor = COLOR_BACKGROUND; ctx = canvas.getContext("2d"); canvas_resize(); setInterval(update_plotter, 1000 / 60); } function plotter_to_esp8266(){ 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 = plotter_init; </script> </head> <body onresize="canvas_resize()"> <h1 id="header">ESP8266 - 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="plotter_to_esp8266();">Connect</button> </div> </body> </html> )=====";
    • Jetzt hast du den Code in zwei Dateien: newbiely.com.ino und index.h
    • Klicke in der Arduino-IDE auf Hochladen, um den Code auf den ESP8266 hochzuladen.
    • Öffne den seriellen Monitor
    • Sieh dir das Ergebnis im seriellen Monitor an.
    COM6
    Send
    Connecting to WiFi... Connected to WiFi ESP8266 Web Server's IP address IP address: 192.168.0.2
    Autoscroll Show timestamp
    Clear output
    9600 baud  
    Newline  
    • Notieren Sie sich die angezeigte IP-Adresse und geben Sie diese Adresse in die Adresszeile eines Webbrowsers auf Ihrem Smartphone oder PC ein.
    • Sie sehen die Webseite wie unten dargestellt:
    ESP8266 NodeMCU Plotter-Webbrowser
    • Klicken Sie auf die CONNECT-Schaltfläche, um die Webseite über WebSocket mit dem ESP8266 zu verbinden.
    • Sie sehen die vom Plotter dargestellten Daten wie im untenstehenden Bild.
    ESP8266 NodeMCU-Webgraph
    • Sie können den seriellen Plotter in der Arduino-IDE öffnen, um ihn mit dem Webplotter im Webbrowser zu vergleichen.

    ※ Notiz:

    • Wenn Sie den HTML-Inhalt in der index.h ändern und nichts an der newbiely.com.ino-Datei berühren, wird die Arduino-IDE den HTML-Inhalt beim Kompilieren und Hochladen des Codes auf dem ESP8266 nicht aktualisieren.
    • Um die Arduino-IDE dazu zu bringen, den HTML-Inhalt in diesem Fall zu aktualisieren, nehmen Sie eine Änderung in der newbiely.com.ino-Datei vor (z. B. eine leere Zeile hinzufügen, einen Kommentar hinzufügen ...).

    Zeile für Zeile Code-Erklärung

    Der obige ESP8266-Code enthält eine zeilenweise Erklärung. Bitte lesen Sie die Kommentare im Code!

※ UNSERE NACHRICHTEN

  • Sie können gerne den Link zu diesem Tutorial teilen. Bitte verwenden Sie jedoch unsere Inhalte nicht auf anderen Websites. Wir haben viel Mühe und Zeit in die Erstellung der Inhalte investiert, bitte respektieren Sie unsere Arbeit!