项目目标:1连接WiFi自动弹出网页
2通过网页控制LED。
项目硬件:Nodemcu板
开发环境:VScode PlatformIO
主要技术: AJAX CSS ESP8266 NodeMCU with VS Code and PlatformIO:上传文件到文件系统(LittleFS)
工程源码
PlatformIO设置
[env:nodemcuv2]
platform = espressif8266
board = nodemcuv2
framework = arduino
board_build.filesystem = littlefs
monitor_speed = 115200
upload_speed = 921600
lib_deps =
me-no-dev/ESPAsyncTCP@^1.2.2
esphome/ESPAsyncWebServer-esphome@^2.1.0
PlatformIO源码:
#ifdef ESP32
#include <WiFi.h>
#include <AsyncTCP.h>
#else
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#endif
#include <DNSServer.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include "ESPAsyncWebServer.h"
#include "FS.h"
#include <LittleFS.h>
const int led_output = 2;
DNSServer dnsServer;
AsyncWebServer server(80);
class CaptiveRequestHandler : public AsyncWebHandler {
public:
CaptiveRequestHandler() {}
virtual ~CaptiveRequestHandler() {}
bool canHandle(AsyncWebServerRequest *request){
//request->addInterestingHeader("ANY");
return true;
}
void handleRequest(AsyncWebServerRequest *request) {
request->send(LittleFS, "/index.html","text/html", false); //连接WiFi自动弹出认证页面
}
};
void setupServer(){
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/index.html","text/html", false);
Serial.println("Client Connected");
});
// Receive an HTTP GET request
server.on("/ON", HTTP_GET, [] (AsyncWebServerRequest *request) {
digitalWrite(led_output, LOW);
request->send(200, "text/plain", "OK");
});
// Receive an HTTP GET request
server.on("/OFF", HTTP_GET, [] (AsyncWebServerRequest *request) {
digitalWrite(led_output, HIGH);
request->send(200, "text/plain", "OK");
});
}
void setup(){
//your other setup stuff...
Serial.begin(115200);
pinMode(led_output, OUTPUT);
digitalWrite(led_output, HIGH);
if(!LittleFS.begin()){
Serial.println("An Error has occurred while mounting LITTLEFS");
return;
}
Serial.println();
Serial.println("Setting up AP Mode");
WiFi.mode(WIFI_AP);
WiFi.softAP("esp-captive");
Serial.print("AP IP address: ");Serial.println(WiFi.softAPIP());
Serial.println("Setting up Async WebServer");
setupServer();
Serial.println("Starting DNS Server");
dnsServer.start(53, "*", WiFi.softAPIP());
server.addHandler(new CaptiveRequestHandler()).setFilter(ON_AP_FILTER);//only when requested from AP
//more handlers...
server.begin();
Serial.println("All Done!");
}
void loop(){
dnsServer.processNextRequest();
}
代码原理
此代码与 ESP32 和 ESP8266 板兼容,但我们定义 LED 状态的部分除外。对于 ESP8266,与 ESP32 相比,板载 LED 的工作逻辑相反。要打开板载 LED,发送一个低信号,要关闭它,发送一个高信号。这与 ESP32 的情况相反。
引用库
首先,我们将包含该项目所需的所有必要库。由于此代码与 ESP32 和 ESP8266 兼容,因此这两个库(无线网络.h和ESP8266WiFi.h) 被定义。该库将有助于在我们的 ESP 模块与无线网络之间建立连接。我们还将导入我们之前安装的两个库,ESPAsyncWebServer库和ESPAsyncTCP库。
#ifdef ESP32
#include <WiFi.h>
#include <AsyncTCP.h>
#else
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#endif
设置输出GPIO
然后,我们将定义变量 led_output 来保存连接板载 LED 的 GPIO 引脚,即,GPIO2.
const int led_output = 2;
创建 AsyncWebServer 对象
AsyncWebServer 对象将用于设置 ESP Web 服务器。我们将传递默认的 HTTP 端口 80 作为构造函数的输入。这将是服务器侦听请求的端口。
AsyncWebServer server(80);
ESP32/ESP8266 处理请求
在本节中,我们将讨论我们的 ESP 板将如何处理不同 URL 上的请求。
/ 请求
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/index.html","text/html", false);
Serial.println("Client Connected");
});
/ON请求
server.on("/ON", HTTP_GET, [] (AsyncWebServerRequest *request) {
digitalWrite(led_output, LOW);
request->send(200, "text/plain", "OK");
});
我们将使用server.on()服务器对象上的方法来监听传入的 HTTP 请求并相应地执行函数。GPIO2 的输出状态将通过 digitalWrite() 函数设置为 LOW。
/OFF 请求
// Receive an HTTP GET request
server.on("/OFF", HTTP_GET, [] (AsyncWebServerRequest *request) {
digitalWrite(led_output, HIGH);
request->send(200, "text/plain", "OK");
});
我们将使用server.on()服务器对象上的方法来监听传入的 HTTP 请求并相应地执行函数。GPIO2 的输出状态将通过 digitalWrite() 函数设置为HIGH。
要启动服务器,我们将在服务器对象上调用 begin()。
server.begin();
服务器网页源码
<!DOCTYPE HTML><html>
<head>
<title>ESP Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: Times New Roman; text-align: center; margin:0px auto; padding-top: 30px;}
.button {
padding: 10px 20px;
font-size: 24px;
text-align: center;
outline: none;
color: #fff;
background-color: #ff0522;
border: none;
border-radius: 15px;
cursor: pointer;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
.button:hover {background-color: #ff0522 }
.button:active {
background-color: #1fe036;
transform: translateY(2px);
}
</style>
</head>
<body>
<h1>ESP瞬时开关服务器</h1>
<button class="button" onmousedown="toggleCheckbox('ON');" ontouchstart="toggleCheckbox('ON');" onmouseup="toggleCheckbox('OFF');" ontouchend="toggleCheckbox('OFF');">瞬时开关:按压开启</button>
<script>
function toggleCheckbox(x) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/" + x, true);
xhr.send();
}
</script>
</body>
定义按钮
现在,我们将创建瞬时开关按钮。我们将在里面定义按钮<button></button>标签。我们将提供不同的属性和文本,如下所示:
<button class="button" onmousedown="toggleCheckbox('ON');" ontouchstart="toggleCheckbox('ON');" onmouseup="toggleCheckbox('OFF');" ontouchend="toggleCheckbox('OFF');">Momentary Switch: Press to Turn ON</button>
在按钮上将显示以下文本瞬时开关:按下开启. 除此之外,我们还将包括属性。
首先,类将包含瞬时开关的名称。在我们的例子中,我们将其命名为“按钮”。这将用于在设置网页样式时引用开关。
其次,onmousedown 是事件的属性。我们将调用toggleCheckbox()以 'ON' 作为参数的函数,以防按下按钮。这是我们稍后会谈到的 JavaScript 函数。通过此功能,将向 ESP32/ESP8266 板发出 HTTP GET 请求,将输出状态变为高电平。
第三,onmousestart 也将调用相同的函数与相同的参数toggleCheckbox('ON'). 这对于具有触摸屏的设备很有用功能。
第四,onmouseup 会调用toggleCheckbox()函数,但内部传递的参数是'OFF'。每当释放按钮时都会调用它。该函数将向 ESP 模块发出 GET 请求以将状态更改为 LOW。
最后,ontouchend 将用于具有触摸屏的设备。这将与 onmouseup 类似。
toggleCheckbox() 函数
function toggleCheckbox(x) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/" + x, true);
xhr.send();
}
接下来,我们将定义toggleCheckbox()功能。这是我们在上面定义瞬时开关按钮的属性时调用的 JavaScript 函数。通过此函数,将向 ESP 模块发出关于打开或关闭 LED 的 HTTP GET 请求。每当按下或释放按钮时,它将创建 HTTP GET 请求。这将通过在 /ON 或 /OFF URL 上重定向它来完成。
在这个函数中,我们使用 XMLHttpRequest。这将允许我们在 JavaScript 中发出 HTTP 请求。要向我们发出 HTTP GET 请求,我们将遵循三个步骤:
首先,我们将创建一个 XMLHttpRequest,如下所示:
var xhr = new XMLHttpRequest();
其次,我们将使用xhr.open()方法。在其中,我们将传递三个参数。第一个参数指定 HTTP 方法的类型,在我们的例子中是 GET。第二个参数是 ESP32/ESP8266 请求的 URL。在我们的例子中,它将是 /ON 或 /OFF URL,具体取决于按钮的状态。最后一个参数是 true,它指定请求是异步的。
xhr.open("GET", "/" + x, true);
最后,我们将使用xhr.send()打开连接。我们的服务器(ESP32/ESP8266)现在可以在用户与按钮交互时接收 HTTP GET 请求。
xhr.send();
关于css
CSS :active 选择器
.button:active {
background-color: #1fe036;
transform: translateY(2px);
}
当按钮有效时,背景颜色设置为绿色,
CSS transform 属性
定义和用法
transform 属性向元素应用 2D 或 3D 转换。该属性允许我们对元素进行旋转、缩放、移动或倾斜。
translateY(y) 定义转换,只是用 Y 轴的值。
网页初始状态,按钮没有按下