Arduino - Webserver met Meerdere Pagina's
In deze tutorial ontdekken we hoe u een Arduino verandert in een webserver die meerdere pagina's tegelijk kan verwerken, zoals index.html, temperature.html, led.html, error_404.html en error_405.html. De inhoud van elke pagina, inclusief HTML, CSS en JavaScript, wordt opgeslagen in aparte bestanden in de Arduino IDE. Door de Arduino Webserver te benaderen vanuit een webbrowser op uw pc of smartphone, kunt u sensoren en actuatoren die gekoppeld zijn aan de Arduino via het web bekijken en aansturen. Bovendien wordt de webserver zo opgezet dat pagina’s bereikbaar zijn met én zonder de extensie .html.
Door deze tutorial te volgen, kunt u uw Arduino omzetten in een webserver met enkele handige functies:
Meerdere webpagina's zijn gelijktijdig actief.
De HTML-inhoud (inclusief HTML, CSS en Javascript) van elke pagina wordt per pagina apart in een eigen bestand bewaard.
De HTML-inhoud kan dynamisch worden aangepast met realtime waarden van sensoren, waardoor de webpagina’s interactief en responsief zijn.
U kunt de pagina’s benaderen met of zonder de .html-extensie. Bijvoorbeeld: http://192.168.0.2/led en http://192.168.0.2/led.html leiden naar dezelfde LED-bedieningspagina.
De webserver ondersteunt het afhandelen van HTTP-foutcodes zoals 404 Not Found en 405 Method Not Allowed.
Het klinkt misschien complex, maar maak u geen zorgen! Deze handleiding begeleidt u stap voor stap, en de code is beginnersvriendelijk, zodat u eenvoudig uw eigen Arduino-webserver kunt maken.
Of u kunt de volgende kits kopen:
Openbaarmaking: Sommige van de links in deze sectie zijn Amazon-affiliate links. We kunnen een commissie ontvangen voor aankopen die via deze links worden gedaan, zonder extra kosten voor u. We waarderen uw steun.
Als u nog niet bekend bent met de Arduino Uno R4 en het concept van een Webserver (inclusief pinout, werking en programmeren), kunt u deze tutorials raadplegen:
Wanneer een webbrowser een HTTP-request naar de Arduino stuurt, moet de Arduino zo geprogrammeerd zijn dat hij de volgende taken uitvoert:
Een webserver opzetten die kan luisteren naar HTTP-verzoeken van de browser.
De eerste regel van de HTTP-request header uitlezen zodra een HTTP-verzoek binnenkomt.
De verzoeken routeren op basis van die eerste regel, om te bepalen welke webpagina de Arduino moet terugsturen.
(Optioneel) De HTTP-request header analyseren om eventuele bedieningscommando’s van de gebruiker te herkennen.
(Optioneel) Apparaten die aan de Arduino verbonden zijn besturen op basis van ontvangen commando’s.
Een HTTP-response terugsturen naar de webbrowser, met daarin:
Door deze taken uit te voeren, kan de Arduino effectief HTTP-verzoeken verwerken en passende antwoorden teruggeven aan de browser, waardoor u via het web interactie heeft met aangesloten apparaten.
De routeringsfunctie is het belangrijkste onderdeel en wordt later uitgebreid toegelicht. Andere onderdelen worden behandeld in de Arduino - Webserver tutorial. Na het begrijpen van het routeringsalgoritme bekijken we de volledige code voor een webserver met meerdere pagina’s.
Voordat u de code voor de routeringsfunctie schrijft, maakt u een lijst van webpagina’s en bijbehorende HTTP-methodes die beschikbaar zullen zijn op de Arduino. In deze tutorial ondersteunen we alleen de GET-methode. U kunt dit later eenvoudig uitbreiden met andere methodes indien nodig. Voorbeeldlijst:
GET home pagina
GET temperatuur pagina
GET deur pagina
GET led pagina
Daarna maakt u een lijst van HTTP-request headers van de eerste regel, correspondeerd aan de pagina’s:
GET home pagina:
GET temperatuur pagina:
GET deur pagina:
GET led pagina:
Samengevat is de lijst als volgt:
GET /
GET /index.html
GET /temperature.html
GET /door.html
GET /led.html
Hieronder vindt u de volledige Arduino-code die een webserver met meerdere pagina’s maakt. Om het simpel te houden is de HTML-inhoud van elke pagina eenvoudig en direct in de Arduino-code ingebed. In het volgende deel leert u hoe u de HTML-inhoud van elke pagina in aparte bestanden kunt plaatsen, waardoor de code overzichtelijker en beter beheersbaar wordt.
#include <UnoR4WiFi_WebServer.h>
const char WIFI_SSID[] = "YOUR_WIFI_SSID";
const char WIFI_PASSWORD[] = "YOUR_WIFI_PASSWORD";
UnoR4WiFi_WebServer server;
float getTemperature() {
float temp_x100 = random(0, 10000);
return temp_x100 / 100;
}
void handleHome(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) {
server.sendResponse(client, "This is home page");
}
void handleTemperature(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) {
server.sendResponse(client, "This is temperature page");
}
void handleDoor(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) {
server.sendResponse(client, "This is door page");
}
void handleLed(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) {
server.sendResponse(client, "This is LED page");
}
void handleNotFound(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) {
server.sendResponse(client, "Page Not Found");
}
void setup() {
Serial.begin(9600);
delay(1000);
Serial.println("Arduino Uno R4 WiFi - Multi-Page Web Server");
Serial.print("Connecting to ");
Serial.println(WIFI_SSID);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" connected!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
server.addRoute("/", handleHome);
server.addRoute("/index", handleHome);
server.addRoute("/index.html", handleHome);
server.addRoute("/temperature", handleTemperature);
server.addRoute("/temperature.html", handleTemperature);
server.addRoute("/door", handleDoor);
server.addRoute("/door.html", handleDoor);
server.addRoute("/led", handleLed);
server.addRoute("/led.html", handleLed);
server.setNotFoundHandler(handleNotFound);
server.begin();
Serial.println("\n=== Web Server Ready! ===");
Serial.print("Visit: http://");
Serial.println(WiFi.localIP());
}
void loop() {
server.handleClient();
}
Open de Library Manager door te klikken op het Library Manager icoon aan de linkerzijde van de Arduino IDE.
Zoek naar Web Server for Arduino Uno R4 WiFi en selecteer de Web Server bibliotheek van DIYables.
Klik op de Installeren knop om de Web Server bibliotheek toe te voegen.
Kopieer bovenstaande code en open deze in de Arduino IDE.
Pas de WiFi-gegevens (SSID en wachtwoord) aan in de code naar uw eigen netwerk.
Klik op de Upload knop in de Arduino IDE om de code naar uw Arduino te uploaden.
Open de Seriële Monitor.
Bekijk het resultaat in de Seriële Monitor.
Connecting to YOUR_WIFI_SSID
connected!
IP address: 192.168.0.254
Starting web server on IP: 192.168.0.254
=== Web Server Ready! ===
Visit: http://192.168.0.254
U ziet een IP-adres in de Seriële Monitor, bijvoorbeeld: 192.168.0.2
Typ de volgende adressen één voor één in de adresbalk van uw webbrowser op smartphone of pc.
192.168.0.2
192.168.0.2/index
192.168.0.2/index.html
192.168.0.2/led
192.168.0.2/led.html
192.168.0.2/door
192.168.0.2/door.html
192.168.0.2/temperature
192.168.0.2/temperature.html
192.168.0.2/blabla
192.168.0.2/blabla.html
Let op dat u het IP-adres 192.168.0.2 vervangt door het adres dat in uw Seriële Monitor staat.
U ziet de volgende pagina’s: home pagina, led pagina, deur pagina, temperatuur pagina en een Niet Gevonden pagina.
U kunt ook de output op de Seriële Monitor controleren.
De vorige code heeft erg simpele HTML-inhoud per pagina. Maar als u een mooie interface met veel HTML wilt maken, wordt de code al snel groot en onoverzichtelijk. Om dit te vermijden leren we nu hoe u de HTML kunt scheiden van de Arduino-code. Zo houdt u de HTML in aparte bestanden, makkelijker te beheren en bewerken.
Open de Arduino IDE.
Maak een nieuw project en geef het een naam, bijvoorbeeld ArduinoWebServer.ino.
Kopieer de onderstaande code en plak deze in dat bestand.
#include <UnoR4WiFi_WebServer.h>
#include "index.h"
#include "temperature.h"
#include "door.h"
#include "led.h"
#include "error_404.h"
const char WIFI_SSID[] = "YOUR_WIFI_SSID";
const char WIFI_PASSWORD[] = "YOUR_WIFI_PASSWORD";
UnoR4WiFi_WebServer server;
float getTemperature() {
float temp_x100 = random(0, 10000);
return temp_x100 / 100;
}
void handleHome(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) {
server.sendResponse(client, HTML_CONTENT_HOME);
}
void handleTemperature(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) {
String html = String(HTML_CONTENT_TEMPERATURE);
html.replace("TEMPERATURE_MARKER", String(getTemperature(), 2));
server.sendResponse(client, html.c_str());
}
void handleDoor(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) {
String html = String(HTML_CONTENT_DOOR);
html.replace("DOOR_STATE_MARKER", "OPENED");
server.sendResponse(client, html.c_str());
}
void handleLed(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) {
String html = String(HTML_CONTENT_LED);
html.replace("LED_STATE_MARKER", "OFF");
server.sendResponse(client, html.c_str());
}
void handleNotFound(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) {
String html = String(HTML_CONTENT_404 );
server.sendResponse(client, html.c_str());
}
void setup() {
Serial.begin(9600);
delay(1000);
Serial.println("Arduino Uno R4 WiFi - Multi-Page Web Server");
Serial.print("Connecting to ");
Serial.println(WIFI_SSID);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" connected!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
server.addRoute("/", handleHome);
server.addRoute("/index", handleHome);
server.addRoute("/index.html", handleHome);
server.addRoute("/temperature", handleTemperature);
server.addRoute("/temperature.html", handleTemperature);
server.addRoute("/door", handleDoor);
server.addRoute("/door.html", handleDoor);
server.addRoute("/led", handleLed);
server.addRoute("/led.html", handleLed);
server.setNotFoundHandler(handleNotFound);
server.begin();
Serial.println("\n=== Web Server Ready! ===");
Serial.print("Visit: http://");
Serial.println(WiFi.localIP());
}
void loop() {
server.handleClient();
}
Pas de WiFi-gegevens (SSID en wachtwoord) in de code aan naar uw gegevens.
Maak het bestand index.h aan in de Arduino IDE door:
const char *HTML_CONTENT_HOME = R""""(
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="data:,">
<title>Home Page</title>
</head>
<body>
<h1>Welcome to the Home Page</h1>
<ul>
<li><a href="/led">LED Page</a></li>
<li><a href="/temperature">Temperature Page</a></li>
<li><a href="/door">Door Page</a></li>
</ul>
</body>
</html>
)"""";
const char *HTML_CONTENT_TEMPERATURE = R""""(
<!DOCTYPE html>
<html>
<head>
<title>Arduino - Web Temperature</title>
<meta name="viewport" content="width=device-width, initial-scale=0.7, maximum-scale=0.7">
<meta charset="utf-8">
<link rel="icon" href="https://diyables.io/images/page/diyables.svg">
<style>
body { font-family: "Georgia"; text-align: center; font-size: width/2pt;}
h1 { font-weight: bold; font-size: width/2pt;}
h2 { font-weight: bold; font-size: width/2pt;}
button { font-weight: bold; font-size: width/2pt;}
</style>
<script>
var cvs_width = 200, cvs_height = 450;
function init() {
var canvas = document.getElementById("cvs");
canvas.width = cvs_width;
canvas.height = cvs_height + 50;
var ctx = canvas.getContext("2d");
ctx.translate(cvs_width/2, cvs_height - 80);
update_view(TEMPERATURE_MARKER);
}
function update_view(temp) {
var canvas = document.getElementById("cvs");
var ctx = canvas.getContext("2d");
var radius = 70;
var offset = 5;
var width = 45;
var height = 330;
ctx.clearRect(-cvs_width/2, -350, cvs_width, cvs_height);
ctx.strokeStyle="blue";
ctx.fillStyle="blue";
var x = -width/2;
ctx.lineWidth=2;
for (var i = 0; i <= 100; i+=5) {
var y = -(height - radius)*i/100 - radius - 5;
ctx.beginPath();
ctx.lineTo(x, y);
ctx.lineTo(x - 20, y);
ctx.stroke();
}
ctx.lineWidth=5;
for (var i = 0; i <= 100; i+=20) {
var y = -(height - radius)*i/100 - radius - 5;
ctx.beginPath();
ctx.lineTo(x, y);
ctx.lineTo(x - 25, y);
ctx.stroke();
ctx.font="20px Georgia";
ctx.textBaseline="middle";
ctx.textAlign="right";
ctx.fillText(i.toString(), x - 35, y);
}
ctx.lineWidth=16;
ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2 * Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.rect(-width/2, -height, width, height);
ctx.stroke();
ctx.beginPath();
ctx.arc(0, -height, width/2, 0, 2 * Math.PI);
ctx.stroke();
ctx.fillStyle="#e6e6ff";
ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.rect(-width/2, -height, width, height);
ctx.fill();
ctx.beginPath();
ctx.arc(0, -height, width/2, 0, 2 * Math.PI);
ctx.fill();
ctx.fillStyle="#ff1a1a";
ctx.beginPath();
ctx.arc(0, 0, radius - offset, 0, 2 * Math.PI);
ctx.fill();
temp = Math.round(temp * 100) / 100;
var y = (height - radius)*temp/100.0 + radius + 5;
ctx.beginPath();
ctx.rect(-width/2 + offset, -y, width - 2*offset, y);
ctx.fill();
ctx.fillStyle="red";
ctx.font="bold 34px Georgia";
ctx.textBaseline="middle";
ctx.textAlign="center";
ctx.fillText(temp.toString() + "°C", 0, 100);
}
window.onload = init;
</script>
</head>
<body>
<h1>Arduino - Web Temperature</h1>
<canvas id="cvs"></canvas>
</body>
</html>
)"""";
const char *HTML_CONTENT_DOOR = R""""(
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="data:,">
<title>Door Page</title>
</head>
<body>
<h1>Door Page</h1>
<p>Door State: <span style="color: red;">DOOR_STATE_MARKER</span></p>
</body>
</html>
)"""";
const char *HTML_CONTENT_LED = R""""(
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="data:,">
<title>LED Page</title>
</head>
<body>
<h1>LED Page</h1>
<p>LED State: <span style="color: red;">LED_STATE_MARKER</span></p>
</body>
</html>
)"""";
const char *HTML_CONTENT_404 = R""""(
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="data:,">
<title>404 - Page Not Found</title>
<style>
h1 {color: #ff4040;}
</style>
</head>
<body>
<h1>404</h1>
<p>Oops! The page you are looking for could not be found on Arduino Web Server.</p>
<p>Please check the URL or go back to the <a href="/">homepage</a>.</p>
<p>Or check <a href="https://arduinogetstarted.com/tutorials/arduino-web-server-multiple-pages"> Arduino Web Server</a> tutorial.</p>
</body>
</html>
)"""";
Klik op de Upload knop in de Arduino IDE om de code naar de Arduino te uploaden.
Bezoek de webpagina’s van de Arduino via webbrowser één voor één, zoals eerder. U ziet alle pagina’s netjes geladen:
※ Notiz:
Als u wijzigingen aanbrengt in de HTML-inhoud binnen het index.h bestand maar niets verandert in het ArduinoWebServer.ino bestand, dan zal de Arduino IDE de HTML-inhoud niet vernieuwen of bijwerken wanneer u de code compileert en uploadt.
Om de Arduino IDE in dit geval te dwingen de HTML-inhoud te updaten, moet u een kleine aanpassing doen in het ArduinoWebServer.ino bestand. Bijvoorbeeld door een lege regel toe te voegen of een commentaarregel in te voegen. Hierdoor detecteert de IDE dat er wijzigingen zijn en worden uw bijgewerkte HTML-bestanden meegenomen bij de upload.