Web Server Multiple Pages#
Arduino - Web Server Multiple Pages —— Arduino Tutorial
Key Points#
多页面服务器;
网页模板写成 .h 头文件
绘图
模板字符串与替换的方法
前置知识#
会单页面的 Web server
注意事项#
如果只修改 .h 头文件,而不修改 .ino 文件,Arduino 不会更新上传新的 .h 文件。解决方法是修改 .ino 主文件,例如加一个空行或空格。
路由#
在 Arduino 服务实现以下路由:
GET /
GET /index.html
GET /temperature.html
GET /door.html
GET /led.html
sample code#
if (HTTP_req.indexOf("GET") == 0) { // check if request method is GET
if (HTTP_req.indexOf("GET / ") > -1 || HTTP_req.indexOf("GET /index.html ") > -1) {
Serial.println("home page");
// TO BE IMPLEMENT
} else if (HTTP_req.indexOf("GET /temperature.html ") > -1) {
Serial.println("temperature page");
// TO BE IMPLEMENT
} else if (HTTP_req.indexOf("GET /door.html ") > -1) {
Serial.println("door page");
// TO BE IMPLEMENT
} else if (HTTP_req.indexOf("GET /led.html ") > -1) {
Serial.println("led page");
// TO BE IMPLEMENT
} else { // 404 Not Found
Serial.println("404 Not Found");
// TO BE IMPLEMENT
}
} else { // 405 Method Not Allowed
Serial.println("405 Method Not Allowed");
// TO BE IMPLEMENT
}
注意,服务器的子功能都是待实现的,但都向串口打印了 debug 信息。
下面的代码增加了不需要 .html 后缀的网址支持:
if (HTTP_req.indexOf("GET") == 0) { // check if request method is GET
if (HTTP_req.indexOf("GET / ") > -1 || HTTP_req.indexOf("GET /index ") > -1 || HTTP_req.indexOf("GET /index.html ") > -1) {
Serial.println("home page");
// TO BE IMPLEMENT
} else if (HTTP_req.indexOf("GET /temperature ") > -1 || HTTP_req.indexOf("GET /temperature.html ") > -1) {
Serial.println("temperature page");
// TO BE IMPLEMENT
} else if (HTTP_req.indexOf("GET /door ") > -1 || HTTP_req.indexOf("GET /door.html ") > -1) {
Serial.println("door page");
// TO BE IMPLEMENT
} else if (HTTP_req.indexOf("GET /led ") > -1 || HTTP_req.indexOf("GET /led.html ") > -1) {
Serial.println("led page");
// TO BE IMPLEMENT
} else { // 404 Not Found
Serial.println("404 Not Found");
// TO BE IMPLEMENT
}
} else { // 405 Method Not Allowed
Serial.println("405 Method Not Allowed");
// TO BE IMPLEMENT
}
多功能分支#
// send the HTTP response
// send the HTTP response header
if (page_id == PAGE_ERROR_404)
client.println("HTTP/1.1 404 Not Found");
if (page_id == PAGE_ERROR_405)
client.println("HTTP/1.1 405 Method Not Allowed");
else
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println(); // the separator between HTTP header and body
// send the simple HTTP response body
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("<head>");
client.println("<link rel=\"icon\" href=\"data:,\">");
client.println("</head>");
String html;
switch (page_id) {
case PAGE_HOME:
client.println("This is home page");
break;
case PAGE_TEMPERATURE:
client.println("This is temperature page");
break;
case PAGE_DOOR:
client.println("This is door page");
break;
case PAGE_LED:
client.println("This is LED page");
break;
case PAGE_ERROR_404:
client.println("Page Not Found");
break;
case PAGE_ERROR_405:
client.println("Method Not Allowed");
break;
}
client.println("</html>");
附完整代码#
/*
* Created by ArduinoGetStarted.com
*
* This example code is in the public domain
*
* Tutorial page: https://arduinogetstarted.com/tutorials/arduino-web-server-multiple-pages
*/
#include <WiFiS3.h>
#define PAGE_HOME 0
#define PAGE_TEMPERATURE 1
#define PAGE_DOOR 2
#define PAGE_LED 3
#define PAGE_ERROR_404 -1
#define PAGE_ERROR_405 -2
const char ssid[] = "YOUR_WIFI"; // change your network SSID (name)
const char pass[] = "YOUR_WIFI_PASSWORD"; // change your network password (use for WPA, or use as key for WEP)
int status = WL_IDLE_STATUS;
WiFiServer server(80);
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(9600);
String fv = WiFi.firmwareVersion();
if (fv < WIFI_FIRMWARE_LATEST_VERSION)
Serial.println("Please upgrade the firmware");
// attempt to connect to WiFi network:
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
server.begin();
// you're connected now, so print out the status:
printWifiStatus();
}
void loop() {
// listen for incoming clients
WiFiClient client = server.available();
if (client) {
// read the first line of HTTP request header
String HTTP_req = "";
while (client.connected()) {
if (client.available()) {
Serial.println("New HTTP Request");
HTTP_req = client.readStringUntil('\n'); // read the first line of HTTP request
Serial.print("<< ");
Serial.println(HTTP_req); // print HTTP request to Serial Monitor
break;
}
}
// read the remaining lines of HTTP request header
while (client.connected()) {
if (client.available()) {
String HTTP_header = client.readStringUntil('\n'); // read the header line of HTTP request
if (HTTP_header.equals("\r")) // the end of HTTP request
break;
//Serial.print("<< ");
//Serial.println(HTTP_header); // print HTTP request to Serial Monitor
}
}
// ROUTING
// This example supports the following:
// - GET /
// - GET /index
// - GET /index.html
// - GET /temperature
// - GET /temperature.html
// - GET /door
// - GET /door.html
// - GET /led
// - GET /led.html
int page_id = 0;
if (HTTP_req.indexOf("GET") == 0) { // check if request method is GET
if (HTTP_req.indexOf("GET / ") > -1 || HTTP_req.indexOf("GET /index ") > -1 || HTTP_req.indexOf("GET /index.html ") > -1) {
Serial.println("home page");
page_id = PAGE_HOME;
} else if (HTTP_req.indexOf("GET /temperature ") > -1 || HTTP_req.indexOf("GET /temperature.html ") > -1) {
Serial.println("temperature page");
page_id = PAGE_TEMPERATURE;
} else if (HTTP_req.indexOf("GET /door ") > -1 || HTTP_req.indexOf("GET /door.html ") > -1) {
Serial.println("door page");
page_id = PAGE_DOOR;
} else if (HTTP_req.indexOf("GET /led ") > -1 || HTTP_req.indexOf("GET /led.html ") > -1) {
Serial.println("led page");
page_id = PAGE_LED;
} else { // 404 Not Found
Serial.println("404 Not Found");
page_id = PAGE_ERROR_404;
}
} else { // 405 Method Not Allowed
Serial.println("405 Method Not Allowed");
page_id = PAGE_ERROR_405;
}
// send the HTTP response
// send the HTTP response header
if (page_id == PAGE_ERROR_404)
client.println("HTTP/1.1 404 Not Found");
if (page_id == PAGE_ERROR_405)
client.println("HTTP/1.1 405 Method Not Allowed");
else
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println(); // the separator between HTTP header and body
// send the simple HTTP response body
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("<head>");
client.println("<link rel=\"icon\" href=\"data:,\">");
client.println("</head>");
String html;
switch (page_id) {
case PAGE_HOME:
client.println("This is home page");
break;
case PAGE_TEMPERATURE:
client.println("This is temperature page");
break;
case PAGE_DOOR:
client.println("This is door page");
break;
case PAGE_LED:
client.println("This is LED page");
break;
case PAGE_ERROR_404:
client.println("Page Not Found");
break;
case PAGE_ERROR_405:
client.println("Method Not Allowed");
break;
}
client.println("</html>");
client.flush();
client.flush();
// give the web browser time to receive the data
delay(10);
// close the connection:
client.stop();
}
}
void printWifiStatus() {
// print your board's IP address:
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
// print the received signal strength:
Serial.print("signal strength (RSSI):");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
}
值得注意的是关闭连接的过程,并不是立即关闭,也不是不关闭,而是 flush, flush, delay, and then stop。
client.flush();
client.flush();
// give the web browser time to receive the data
delay(10);
// close the connection:
client.stop();
分离头文件#
index.h#
/*
* Created by ArduinoGetStarted.com
*
* This example code is in the public domain
*
* Tutorial page: https://arduinogetstarted.com/tutorials/arduino-web-server-multiple-pages
*/
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>
)"""";
temprature.h#
这个页面实现了绘图的效果
/*
* Created by ArduinoGetStarted.com
*
* This example code is in the public domain
*
* Tutorial page: https://arduinogetstarted.com/tutorials/arduino-web-server-multiple-pages
*/
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";
//5-step Degree
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();
}
//20-step Degree
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);
}
// shape
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>
)"""";
door.h#
/*
* Created by ArduinoGetStarted.com
*
* This example code is in the public domain
*
* Tutorial page: https://arduinogetstarted.com/tutorials/arduino-web-server-multiple-pages
*/
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>
)"""";
led.h#
/*
* Created by ArduinoGetStarted.com
*
* This example code is in the public domain
*
* Tutorial page: https://arduinogetstarted.com/tutorials/arduino-web-server-multiple-pages
*/
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>
)"""";
error_404.h#
/*
* Created by ArduinoGetStarted.com
*
* This example code is in the public domain
*
* Tutorial page: https://arduinogetstarted.com/tutorials/arduino-web-server-multiple-pages
*/
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>
)"""";
error_405.h#
/*
* Created by ArduinoGetStarted.com
*
* This example code is in the public domain
*
* Tutorial page: https://arduinogetstarted.com/tutorials/arduino-web-server-multiple-pages
*/
const char *HTML_CONTENT_405 = 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>405 - Method Not Allowed</title>
<style>
h1 {color: #ff4040;}
</style>
</head>
<body>
<h1>405 - Method Not Allowed</h1>
<p>Oops! The requested method is not allowed for this resource.</p>
<p>Please check your request 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>
)"""";
main.ino#
Diff code#
...
#include <WiFiS3.h>
#include "index.h"
#include "temperature.h"
#include "door.h"
#include "led.h"
#include "error_404.h"
#include "error_405.h"
#define PAGE_HOME 0
#define PAGE_TEMPERATURE 1
...
// send the HTTP response
// send the HTTP response header
if (page_id == PAGE_ERROR_404)
client.println("HTTP/1.1 404 Not Found");
if (page_id == PAGE_ERROR_405)
client.println("HTTP/1.1 405 Method Not Allowed");
else
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println(); // the separator between HTTP header and body
// send the HTTP response body
String html;
switch (page_id) {
case PAGE_HOME:
html = String(HTML_CONTENT_HOME);
break;
case PAGE_TEMPERATURE:
html = String(HTML_CONTENT_TEMPERATURE);
html.replace("TEMPERATURE_MARKER", String(getTemperature(), 2)); // replace the marker by a real value
break;
case PAGE_DOOR:
html = String(HTML_CONTENT_DOOR);
html.replace("DOOR_STATE_MARKER", "OPENED"); // replace the marker by a real value
break;
case PAGE_LED:
html = String(HTML_CONTENT_LED);
html.replace("LED_STATE_MARKER", "OFF"); // replace the marker by a real value
break;
case PAGE_ERROR_404:
html = String(HTML_CONTENT_404);
break;
case PAGE_ERROR_405:
html = String(HTML_CONTENT_405);
break;
}
client.println(html);
client.flush();
// give the web browser time to receive the data
delay(10);
// close the connection:
client.stop();
}
}
...
完整版#
/*
* Created by ArduinoGetStarted.com
*
* This example code is in the public domain
*
* Tutorial page: https://arduinogetstarted.com/tutorials/arduino-web-server-multiple-pages
*/
#include <WiFiS3.h>
#include "index.h"
#include "temperature.h"
#include "door.h"
#include "led.h"
#include "error_404.h"
#include "error_405.h"
#define PAGE_HOME 0
#define PAGE_TEMPERATURE 1
#define PAGE_DOOR 2
#define PAGE_LED 3
#define PAGE_ERROR_404 -1
#define PAGE_ERROR_405 -2
const char ssid[] = "YOUR_WIFI"; // change your network SSID (name)
const char pass[] = "YOUR_WIFI_PASSWORD"; // change your network password (use for WPA, or use as key for WEP)
int status = WL_IDLE_STATUS;
WiFiServer server(80);
float getTemperature() {
// YOUR SENSOR IMPLEMENTATION HERE
// simulate the temperature value
float temp_x100 = random(0, 10000); // a ramdom value from 0 to 10000
return temp_x100 / 100; // return the simulated temperature value from 0 to 100 in float
}
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(9600);
String fv = WiFi.firmwareVersion();
if (fv < WIFI_FIRMWARE_LATEST_VERSION)
Serial.println("Please upgrade the firmware");
// attempt to connect to WiFi network:
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
server.begin();
// you're connected now, so print out the status:
printWifiStatus();
}
void loop() {
// listen for incoming clients
WiFiClient client = server.available();
if (client) {
// read the first line of HTTP request header
String HTTP_req = "";
while (client.connected()) {
if (client.available()) {
Serial.println("New HTTP Request");
HTTP_req = client.readStringUntil('\n'); // read the first line of HTTP request
Serial.print("<< ");
Serial.println(HTTP_req); // print HTTP request to Serial Monitor
break;
}
}
// read the remaining lines of HTTP request header
while (client.connected()) {
if (client.available()) {
String HTTP_header = client.readStringUntil('\n'); // read the header line of HTTP request
if (HTTP_header.equals("\r")) // the end of HTTP request
break;
//Serial.print("<< ");
//Serial.println(HTTP_header); // print HTTP request to Serial Monitor
}
}
// ROUTING
// This example supports the following:
// - GET /
// - GET /index
// - GET /index.html
// - GET /temperature
// - GET /temperature.html
// - GET /door
// - GET /door.html
// - GET /led
// - GET /led.html
int page_id = 0;
if (HTTP_req.indexOf("GET") == 0) { // check if request method is GET
if (HTTP_req.indexOf("GET / ") > -1 || HTTP_req.indexOf("GET /index ") > -1 || HTTP_req.indexOf("GET /index.html ") > -1) {
Serial.println("home page");
page_id = PAGE_HOME;
} else if (HTTP_req.indexOf("GET /temperature ") > -1 || HTTP_req.indexOf("GET /temperature.html ") > -1) {
Serial.println("temperature page");
page_id = PAGE_TEMPERATURE;
} else if (HTTP_req.indexOf("GET /door ") > -1 || HTTP_req.indexOf("GET /door.html ") > -1) {
Serial.println("door page");
page_id = PAGE_DOOR;
} else if (HTTP_req.indexOf("GET /led ") > -1 || HTTP_req.indexOf("GET /led.html ") > -1) {
Serial.println("led page");
page_id = PAGE_LED;
} else { // 404 Not Found
Serial.println("404 Not Found");
page_id = PAGE_ERROR_404;
}
} else { // 405 Method Not Allowed
Serial.println("405 Method Not Allowed");
page_id = PAGE_ERROR_405;
}
// send the HTTP response
// send the HTTP response header
if (page_id == PAGE_ERROR_404)
client.println("HTTP/1.1 404 Not Found");
if (page_id == PAGE_ERROR_405)
client.println("HTTP/1.1 405 Method Not Allowed");
else
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println(); // the separator between HTTP header and body
// send the HTTP response body
String html;
switch (page_id) {
case PAGE_HOME:
html = String(HTML_CONTENT_HOME);
break;
case PAGE_TEMPERATURE:
html = String(HTML_CONTENT_TEMPERATURE);
html.replace("TEMPERATURE_MARKER", String(getTemperature(), 2)); // replace the marker by a real value
break;
case PAGE_DOOR:
html = String(HTML_CONTENT_DOOR);
html.replace("DOOR_STATE_MARKER", "OPENED"); // replace the marker by a real value
break;
case PAGE_LED:
html = String(HTML_CONTENT_LED);
html.replace("LED_STATE_MARKER", "OFF"); // replace the marker by a real value
break;
case PAGE_ERROR_404:
html = String(HTML_CONTENT_404);
break;
case PAGE_ERROR_405:
html = String(HTML_CONTENT_405);
break;
}
client.println(html);
client.flush();
// give the web browser time to receive the data
delay(10);
// close the connection:
client.stop();
}
}
void printWifiStatus() {
// print your board's IP address:
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
// print the received signal strength:
Serial.print("signal strength (RSSI):");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
}