了解如何在两个ESP8266 NodeMCU 板之间建立 Wi-Fi 通信 (HTTP) 以交换数据,而无需连接到互联网(不需要路由器)。
您将ESP8266设置为接入点(服务器),将另一个ESP8266设置为工作站(客户端)。然后,服务器和客户端将通过HTTP请求交换数据(传感器读数)。我们将使用 Arduino IDE 对 ESP8266 板进行编程。
在此示例中,我们将 BME280 传感器读数从一块板发送到另一块板。接收器将在 OLED 显示屏上显示读数。
如果您有 ESP32 开发板,本网站也有esp32客户端与服务端直接通信的教程。
目录
项目概况
为了更好地理解一切是如何工作的,请查看下图。
- ESP8266服务器创建自己的无线网络(ESP8266软接入点)。因此,其他 Wi-Fi 设备可以连接到该网络(SSID:ESP8266-Access-Point,密码:123456789)。
- ESP8266客户端设置为工作站。因此,它可以连接到ESP8266服务器无线网络。
- 客户端可以向服务器发出 HTTP GET 请求,以请求传感器数据或任何其他信息。它只需要使用服务器的 IP 地址在某个路由上发出请求:/temperature、/humidity 或 /pressure。
- 服务器侦听传入的请求,并发送带有读数的适当响应。
- 客户端接收读数并将其显示在OLED显示屏上。
例如,ESP8266 客户端通过在服务器 IP 地址上发出请求,后跟 /temperature、/humidity 和 /pressure (HTTP GET) 向服务器请求温度、湿度和压力。
ESP8266服务器正在侦听这些路由,当发出请求时,它会通过 HTTP 响应发送相应的传感器读数。
所需零件
在本教程中,需要以下部分:
- 2 个ESP8266开发板
- BME280 传感器
- I2C SSD1306 OLED显示屏
- 连接线
- 面包板
安装库
在本教程中,您需要安装以下库:
异步 Web 服务器库
我们将使用以下库来处理 HTTP 请求:
这些库无法通过库管理器进行安装。因此,您需要解压缩库并将它们移动到 Arduino IDE 安装库文件夹。
或者,您可以转到 Sketch > Include Library > Add .ZIP library…,然后选择您刚刚下载的库。
BME280 库
可以通过Arduino库管理器安装以下库。转到“程序”>“包含库”>“管理库”,然后搜索库名称。
I2C SSD1306 OLED 库
要与OLED显示器连接,您需要以下库。这些可以通过Arduino库管理器进行安装。转到“程序”>“包含库”>“管理库”,然后搜索库名称。
您可能还喜欢: 带ESP8266 SSD1306 OLED显示屏完整指南
#1 ESP8266服务器(接入点)
ESP8266服务器是一个接入点 (AP),用于侦听 /temperature、/humidity 和 /pressure URL 上的请求。当它收到这些 URL 上的请求时,它会发送最新的 BME280 传感器读数。
对于测试,我们使用的是 BME280 传感器,但您可以通过修改几行代码(例如:DHT11/DHT22 或 DS18B20)来使用任何其他传感器。
原理图
将ESP8266连接到 BME280 传感器,如下图所示。
BME280型 | ESP8266 |
VIN/VCC封装 | 3.3V |
GND | GND |
SCL | 通用IO 5 (D1) |
SDA | 通用IO 4 (D2) |
#1 ESP8266服务器的Arduino程序
将以下代码上传到您的开发板。
/*
更多Arduino/ESP8266/ESP32等教程请访问: https://www.qutaojiao.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
// Import required libraries
#include <ESP8266WiFi.h>
#include "ESPAsyncWebServer.h"
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
// Set your access point network credentials
const char* ssid = "ESP8266-Access-Point";
const char* password = "123456789";
/*#include <SPI.h>
#define BME_SCK 18
#define BME_MISO 19
#define BME_MOSI 23
#define BME_CS 5*/
Adafruit_BME280 bme; // I2C
//Adafruit_BME280 bme(BME_CS); // hardware SPI
//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
String readTemp() {
return String(bme.readTemperature());
//return String(1.8 * bme.readTemperature() + 32);
}
String readHumi() {
return String(bme.readHumidity());
}
String readPres() {
return String(bme.readPressure() / 100.0F);
}
void setup(){
// Serial port for debugging purposes
Serial.begin(115200);
Serial.println();
// Setting the ESP as an access point
Serial.print("Setting AP (Access Point)…");
// Remove the password parameter, if you want the AP (Access Point) to be open
WiFi.softAP(ssid, password);
IPAddress IP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(IP);
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readTemp().c_str());
});
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readHumi().c_str());
});
server.on("/pressure", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readPres().c_str());
});
bool status;
// default settings
// (you can also pass in a Wire library object like &Wire2)
status = bme.begin(0x76);
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
// Start server
server.begin();
}
void loop(){
}
代码的工作原理
首先包括必要的库。包括 ESP8266WiFi.h 库和 ESPAsyncWebServer.h 库来处理传入的 HTTP 请求。
#include <ESP8266WiFi.h>
#include "ESPAsyncWebServer.h"
包括以下库以与 BME280 传感器连接。
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
在以下变量中,定义接入点网络凭据:
const char* ssid = "ESP8266-Access-Point";
const char* password = "123456789";
我们将 SSID 设置为 ESP8266-Access-Point,但您可以为其指定任何其他名称。您也可以更改密码。默认情况下,它设置为 123456789。
为名为 bme 的 BME280 传感器创建实例。
Adafruit_BME280 bme;
在端口 80 上创建异步 Web 服务器。
AsyncWebServer server(80);
然后,创建三个函数,将温度、湿度和压力作为 String 变量返回。
String readTemp() {
return String(bme.readTemperature());
//return String(1.8 * bme.readTemperature() + 32);
}
String readHumi() {
return String(bme.readHumidity());
}
String readPres() {
return String(bme.readPressure() / 100.0F);
}
在 setup() 中,初始化串行监视器以进行演示。
Serial.begin(115200);
使用前面定义的 SSID 名称和密码将您的ESP8266设置为接入点。
WiFi.softAP(ssid, password);
然后,处理ESP8266将侦听传入请求的路由。
例如,当 ESP8266 服务器收到 /temperature URL 上的请求时,它会将 readTemp() 函数返回的温度作为 char 发送(这就是我们使用 c_str() 方法的原因。
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readTemp().c_str());
});
当 ESP 收到 /humidity 和 /pressure URL 上的请求时,也会发生同样的情况。
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readHumi().c_str());
});
server.on("/pressure", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readPres().c_str());
});
以下行初始化 BME280 传感器。
bool status;
// default settings
// (you can also pass in a Wire library object like &Wire2)
status = bme.begin(0x76);
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
最后,启动服务器。
server.begin();
因为这是一个异步 Web 服务器,所以 loop() 中没有任何内容。
void loop(){
}
测试 ESP8266 服务器
将代码上传到您的主板并打开串行监视器。您应该得到如下内容:
这意味着接入点已成功设置。
现在,为了确保它正在侦听温度、湿度和压力请求,您需要连接到其网络。
在您的智能手机中,转到 Wi-Fi 设置并连接到 ESP8266-Access-Point。密码已123456789。
连接到接入点后,打开浏览器并键入 192.168.4.1/temperature
您应该在浏览器中获取温度值:
尝试以下 URL 路径以获取湿度 192.168.4.1/humidity:
最后,转到 192.168.4.1/pressure URL:
如果您获得有效读数,则意味着一切正常。现在,您需要准备另一块ESP8266板(客户端)来为您提出这些请求,并将它们显示在OLED显示屏上。
#2 ESP8266客户端(站)
ESP8266 客户端是连接到 ESP8266 服务器的 Wi-Fi 站。客户端通过对 /temperature、/humidity 和 /pressure URL 路由发出 HTTP GET 请求,从服务器请求温度、湿度和压力。然后,它在OLED显示屏上显示读数。
原理图
将OLED显示器连接到ESP8266板,如下图所示。
Pin | ESP8266 |
Vin | 3.3V |
GND | GND |
SCL | 通用IO 5 (D1) |
SDA | 通用IO 4 (D2) |
Arduino Sketch for #2 ESP8266 客户端
将以下代码上传到其他ESP8266(客户端):
代码的工作原理
包括用于 Wi-Fi 连接和发出 HTTP 请求的必要库:
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
#include <ESP8266WiFiMulti.h>
您需要创建一个 WiFiMulti 实例。
ESP8266WiFiMulti WiFiMulti;
插入ESP8266服务器网络凭据。如果更改了 ESP8266 服务器中的默认网络凭据,则应在此处更改它们以匹配。
const char* ssid = "ESP8266-Access-Point";
const char* password = "123456789";
然后,保存客户端将发出 HTTP 请求的 URL。ESP8266服务器具有 192.168.4.1 IP 地址,我们将对 /temperature、/humidity 和 /pressure URL 发出请求。
const char* serverNameTemp = "http://192.168.4.1/temperature";
const char* serverNameHumi = "http://192.168.4.1/humidity";
const char* serverNamePres = "http://192.168.4.1/pressure";
包括用于与OLED显示器连接的库:
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
设置OLED显示尺寸:
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
使用您之前定义的大小和 I2C 通信协议创建显示对象。
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
初始化字符串变量,这些变量将保存服务器检索到的温度、湿度和压力读数。
String temperature;
String humidity;
String pressure;
设置每个请求之间的时间间隔。默认情况下,它设置为 5 秒,但您可以将其更改为任何其他间隔。
const long interval = 5000;
在 setup() 中,初始化 OLED 显示屏:
// Address 0x3C for 128x64, you might need to change this value (use an I2C scanner)
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.clearDisplay();
display.setTextColor(WHITE);
注意:如果您的 OLED 显示器不工作,请使用 I2C 扫描仪程序检查其 I2C 地址并相应地更改代码。
将 ESP8266 客户端连接到 ESP8266 服务器网络。
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("Connected to WiFi");
In the loop() 是我们发出 HTTP GET 请求的地方。我们创建了一个名为 httpGETRequest() 的函数,该函数接受我们想要发出请求的 URL 路径作为参数,并将响应作为 String 返回。
可以在项目中使用 next 函数来简化代码:
String httpGETRequest(const char* serverName) {
WiFiClient client;
HTTPClient http;
// Your IP address with path or Domain name with URL path
http.begin(client, serverName);
// Send HTTP POST request
int httpResponseCode = http.GET();
String payload = "--";
if (httpResponseCode>0) {
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
payload = http.getString();
}
else {
Serial.print("Error code: ");
Serial.println(httpResponseCode);
}
// Free resources
http.end();
return payload;
}
我们使用该函数从服务器获取温度、湿度和压力读数。
temperature = httpGETRequest(serverNameTemp);
humidity = httpGETRequest(serverNameHumi);
pressure = httpGETRequest(serverNamePres);
在串行监视器中打印这些读数以进行调试。
Serial.println("Temperature: " + temperature + " *C - Humidity: " + humidity + " % - Pressure: " + pressure + " hPa");
然后,在OLED显示屏中显示温度:
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.print("T: ");
display.print(temperature);
display.print(" ");
display.setTextSize(1);
display.cp437(true);
display.write(248);
display.setTextSize(2);
display.print("C");
湿度:
display.setTextSize(2);
display.setCursor(0, 25);
display.print("H: ");
display.print(humidity);
display.print(" %");
最后,压力读数:
display.setTextSize(2);
display.setCursor(0, 50);
display.print("P:");
display.print(pressure);
display.setTextSize(1);
display.setCursor(110, 56);
display.print("hPa");
display.display();
我们使用计时器而不是undefined器每 x 秒发出一次请求。这就是为什么我们有 previousMillis、currentMillis 变量并使用 millis() 函数的原因。我们有一篇文章展示了计时器和undefined之间的区别,您可能会觉得有用(或阅读ESP8266计时器)。
将程序上传到 #2 ESP8266(客户端)以测试一切是否正常工作。
测试 ESP8266 客户端
当两块板相当接近并通电时,您会看到 ESP #2 每 5 秒从 ESP #1 接收一次新的温度、湿度和压力读数。
这是您应该在ESP8266客户端串行监视器上看到的内容。
传感器读数也显示在OLED中。
就是这样!您的两个ESP8266板正在相互通信。
总结
在本教程中,我们向您展示了如何使用 HTTP 请求将数据从一个ESP8266板发送到另一个板。如果您需要在两块或更多板之间设置无线通信,并且附近没有路由器,则此项目非常有用。