本文旨在向读者介绍使用Esp8266 WiFi板搭建Web Server应用的原理。示例向读者展示了如何创建Web Console,以及如何使Web Console与NodeMcu进行交互。
硬件准备:
NodeMcu
开发环境:
Arduino IDE(1.8.4),IE11
结果预览:
IE11浏览器:
微信浏览器:
NodeMcu串口输出信息:
演示:
核心代码:
wifi_test.ino 代码:
#include "GetCmd.h"
#include <ESP8266WiFi.h>
#define DEBUG
#ifdef DEBUG
#define DBG_PRINT(x) Serial.print(x)
#define DBG_PRINTLN(x) Serial.println(x)
#else
#define DBG_PRINT(x)
#define DBG_PRINTLN(x)
#endif
#define REQ_HEAD "GET /_cmd_"
#define REQ_TAIL " HTTP"
#define WEB_CONSOLE_BUFFER_SIZE 10240
#ifndef STASSID
#define STASSID "ASUS_24G6"
#define STAPSK "12345678"
#endif
const char* ssid = STASSID;
const char* password = STAPSK;
String web_console;
const String pagePart1 = String("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n") +
"<!DOCTYPE html>"+
"<html>"+
"<head>"+
" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1252\">"+
" <meta http-equiv=\"Expires\" content=\"0\">"+
" <meta http-equiv=\"Pragma\" content=\"no-cache\">"+
" <meta http-equiv=\"Cache-control\" content=\"no-cache\">"+
" <meta http-equiv=\"Cache\" content=\"no-cache\">"+
" <title>CONSOLE</title>"+
"</head>"+
"<body onload=\"document.getElementById(\"cmdline\").focus();\">"+
"<form>"+
" <table>"+
" <tbody>"+
" <tr>"+
" <td>Cmdline:<input type=\"text\" id=\"cmdline\" style=\"width:466px\" onkeydown=\"if(event.keyCode==13) {event.preventDefault();test();}\"></td>"+
" <td><input type=\"button\" onclick=\"test()\" value=\"enter\"></td>"+
" </tr>"+
" </tbody>"+
" </table>"+
"</form>"+
"<textarea id=\"con_out\" style=\"color:#00FF00;background-color:#000000\" rows=\"40\" cols=\"80\" readonly=\"readonly\">";
//WEB CONSOLE OUTPUT
const String pagePart2 = String("</textarea>")+
"<p>Create By <a href=\"mailto:firswof@163.com\">FIRSWOF</a></p>"+
"<script language=\"javascript\">"+
"xmlHttp=null;"+
"function test()"+
"{"+
" if (document.getElementById(\"cmdline\").value.length ==0)"+
" return;"+
" try"+
" {"+
" xmlHttp=new XMLHttpRequest();"+
" } "+
" catch(e)"+
" {"+
" try"+
" {"+
" xmlHttp=new ActiveXObject(\"Microsoft.XMLHTTP\");"+
" }"+
" catch(e)"+
" {"+
" alert (\"Your browser does not support XMLHTTP!\");"+
" return;"+
" }"+
" }"+
" xmlHttp.open(\"GET\",\"_cmd_\" + document.getElementById(\"cmdline\").value,false);"+
" xmlHttp.setRequestHeader(\"If-Modified-Since\",\"0\");"+
" xmlHttp.setRequestHeader(\"Cache-Control\",\"no-cache\");"+
" xmlHttp.send(null);"+
" document.getElementById(\"con_out\").innerHTML=xmlHttp.responseText;"+
" document.getElementById(\"cmdline\").value=\"\";"+
" document.getElementById(\"cmdline\").focus();"+
"}"+
"</script>"+
"</body>"+
"</html>";
// Create an instance of the server
// specify the port to listen on as an argument
WiFiServer server(80);
//Web Console Output
void WebPrintln()
{
web_console += ‘\n‘;
}
template<typename T>
void WebPrint(T msg)
{
web_console += msg;
}
template<typename T>
void WebPrintln(T msg)
{
web_console += msg;
web_console += ‘\n‘;
}
void HtmlHexValueToChar(String &src)
{
String tmp;
for(int i=0;i<src.length();i++)
{
if (src[i] == ‘%‘ && i+2<src.length())
{
if(((src[i+1]>=‘0‘ && src[i+1] <=‘9‘) || (src[i+1]>=‘A‘ && src[i+1] <=‘F‘)|| (src[i+1]>=‘a‘ && src[i+1] <=‘f‘)) &&
((src[i+2]>=‘0‘ && src[i+2] <=‘9‘) || (src[i+2]>=‘A‘ && src[i+2] <=‘F‘)|| (src[i+2]>=‘a‘ && src[i+2] <=‘f‘)))
{
tmp += (char)(strtol((String("0x") + src.substring(i+1,i+3)).c_str(), 0, 16) & 0xff);
i+=2;
}
else
tmp += src[i];
}
else
tmp += src[i];
}
src = tmp;
}
//Web Cmd Functions
//Class GetCmd‘s friend function
void SYS_GetCmdList(char** param, uint8_t parCnt)
{
uint8_t idx = 0;
while (getCmd.Cmds[idx].cmdFunc != NULL)
{
WebPrintln(getCmd.Cmds[idx].cmdName);
idx++;
}
}
void CMD_Clear(char** param, uint8_t parCnt)
{
web_console = "";
}
void CMD_GetMillis(char** param, uint8_t parCnt)
{
unsigned long time = millis();
WebPrint(time);
}
void CMD_Echo(char** param, uint8_t parCnt)
{
for(int i=0;i<parCnt;i++)
{
WebPrint("arg[");
WebPrint(i);
WebPrint("]:");
WebPrint(param[i]);
WebPrintln();
}
}
void CMD_Network(char** param, uint8_t parCnt)
{
bool bSucc = false;
if (parCnt >= 1)
{
if (strcmp(param[0], "show")==0)
{
if (parCnt == 1 || ( parCnt > 1 && strcmp(param[1], "all")==0))
{
WebPrint("SSID:\t");
WebPrintln(STASSID);
WebPrint("PWD:\t");
WebPrintln(STAPSK);
bSucc = true;
}
}
}
if (!bSucc)
WebPrintln("Usage: network [show [all]]");
}
void CMD_Ver(char** param, uint8_t parCnt)
{
WebPrintln("Ver:20200812.01");
WebPrintln("Create By FIRSWOF");
}
void setup()
{
Serial.begin(115200);
Serial.println("system running...");
// prepare LED
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, 0);
//Connect to WiFi network
Serial.println();
Serial.println();
Serial.print(F("Connecting to "));
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(F("."));
}
Serial.println();
Serial.println(F("WiFi connected"));
// Start the server
server.begin();
Serial.println(F("Server started"));
// Print the IP address
Serial.println(WiFi.localIP());
getCmd.AddCommand("ls", SYS_GetCmdList);
getCmd.AddCommand("clear", CMD_Clear);
getCmd.AddCommand("echo", CMD_Echo);
getCmd.AddCommand("millis", CMD_GetMillis);
getCmd.AddCommand("network", CMD_Network);
getCmd.AddCommand("ver", CMD_Ver);
WebPrint("\n#NodeMcu>");
}
void loop()
{
// Check if a client has connected
WiFiClient client = server.available();
if (!client) return;
client.setTimeout(3000); // default is 1000
//Wait until the client sends some data
//~ DBG_PRINTLN("new client");
unsigned long timeout = millis() + 3000;
do
{
delay(1);
} while (!client.available() && millis() < timeout);
if (millis() > timeout)
{
Serial.println("timeout");
return;
}
if (web_console.length() > WEB_CONSOLE_BUFFER_SIZE)
web_console = "";
// Read the first line of the request
String req = client.readStringUntil(‘\r‘);
DBG_PRINT(F("raw request:"));
DBG_PRINTLN(req);
// Match the request
int from, end;
from = req.indexOf(F(REQ_HEAD));
end = req.indexOf(F(REQ_TAIL));
if(req.length() == 0)
{
client.flush();
client.stop();
return;
}
else if(req.startsWith("GET / HTTP/1.1"))
{
DBG_PRINTLN("answer ‘GET / HTTP/1.1‘");
client.flush();
client.print(pagePart1 + web_console + pagePart2);
//~ DBG_PRINTLN(web_console);
}
else if(req.startsWith("GET /favicon.ico HTTP/1.1"))
{
client.flush();
client.print("HTTP/1.1 200 OK\r\n");
from = -1;
}
if (from != -1 && end != -1 && end > from + strlen(REQ_HEAD))
{
req = req.substring(from + strlen(REQ_HEAD), end);
HtmlHexValueToChar(req);
Serial.print(F("request:"));
Serial.println(req);
WebPrintln(req);
if(!getCmd.CmdParser(req.c_str()))
{
WebPrint("invalid cmd");
}
WebPrint("\n#NodeMcu>");
client.flush();
client.print(web_console);
//~ DBG_PRINTLN(web_console);
}
}