ESP8266 NodeMCU:ESP-NOW Web 服务器传感器仪表板(ESP-NOW + Wi-Fi)
在本项目中,您将学习如何使用 ESP8266 NodeMCU 板托管 Web 服务器并同时使用 ESP-NOW 通信协议。您可以让多个 ESP8266 板通过 ESP-NOW 将传感器读数发送到一个 ESP8266 接收器,该接收器在网络服务器上显示所有读数。软件代码使用 Arduino IDE 进行编程。
同时使用 ESP-NOW 和 Wi-Fi
如果您想使用 Wi-Fi 托管 Web 服务器并同时使用 ESP-NOW 从其他开发板接收传感器读数,则需要考虑一些事项:
- ESP8266 发送板必须使用与接收板相同的 Wi-Fi 通道。
- 接收板的 Wi-Fi 信道由您的 Wi-Fi 路由器自动分配。
- 接收板的Wi-Fi模式必须是接入点和站点(WIFI_AP_STA).
- 您可以手动设置相同的 Wi-Fi 通道,也可以在发送器上添加简单的代码,将其 Wi-Fi 通道设置为与接收板相同的 Wi-Fi 通道。
项目概况
下图显示了我们将构建的项目的概览。
- 有两块 ESP8266 发送板,通过 ESP-NOW将BME280温度和湿度读数发送到一块 ESP8266 接收板( ESP-NOW 多对一配置);
- ESP8266 接收板接收数据包并在网络服务器上显示读数;
- 每次使用服务器发送事件 (SSE) 接收到新读数时,网页都会自动更新。
- 该网页还显示了上次使用 JavaScript 更新读数的时间。
前提条件
在继续此项目之前,请确保检查以下先决条件。
开发环境
我们将使用 Arduino IDE 对 ESP8266 板进行编程,因此在继续本教程之前,请确保您的 Arduino IDE 中安装了 ESP8266 板。
- 在 Arduino IDE(Windows、Mac OS X 和 Linux)中安装 ESP8266 开发板
BME280 图书馆
ESP8266 发送板将从 BME280 传感器发送温度和湿度读数。
要从 BME280 传感器读取数据,我们将使用Adafruit_BME280 库。要使用此库,您还需要安装 Adafruit Unified Sensor 库。按照后续步骤安装这些库。
在搜索框中搜索“ adafruit bme280 ”并安装库。
要使用 BME280 库,您还需要安装 Adafruit_Sensor 库。按照以下步骤在您的 Arduino IDE 中安装该库:
转到 Sketch > Include Library > Manage Libraries ,然后在搜索框中 键入“ Adafruit Unified Sensor ”。一直向下滚动以找到库并安装它。
要了解有关 BME280 温度、湿度和压力传感器的更多信息,请阅读我们的指南:ESP8266 和 BME280 使用 Arduino IDE(压力、温度、湿度)。
异步 Web 服务器库
要构建 Web 服务器,您需要安装以下库:
- ESPAsyncWeb服务器
- ESPA同步TCP
这些库无法通过 Arduino 库管理器安装,因此您需要将库文件复制到 Arduino Installation Libraries 文件夹中。或者,在您的 Arduino IDE 中,您可以转到 Sketch > Include Library > Add .zip Library 并选择您刚刚下载的库。
Arduino_JSON 库
您需要安装 Arduino_JSON 库。您可以在 Arduino IDE 库管理器中安装此库。只需转到 Sketch > Include Library > Manage Libraries 并搜索库名称,如下所示:
所需硬件
要学习本教程,您需要多个 ESP8266 开发板。我们将使用三个 ESP8266 板。您还需要:
- 3x ESP8266 (阅读 最佳 ESP8266 开发板)
- 2x BME280 传感器– ESP8266 的 BME280 指南
- 面包板
- 跳线
获取接收板MAC地址
要通过 ESP-NOW 发送消息,您需要知道接收板的。每块板都有一个唯一的 MAC 地址。
将以下代码上传到您的 ESP8266 接收板以获取其 MAC 地址。
// 获取和更改ESP MAC地址的完整代码:#ifdef ESP32#include <WiFi.h>
#else#include <ESP8266WiFi.h>
#endifvoid setup(){Serial.begin(115200);Serial.println();Serial.print("ESP Board MAC Address: ");Serial.println(WiFi.macAddress());
}void loop(){}
上传代码后,按下 RST/EN 按钮,MAC 地址应该显示在串口监视器上。
ESP8266 接收器(ESP-NOW + Web 服务器)
ESP8266 NodeMCU 接收板接收来自发送板的数据包,并托管一个网络服务器以显示最新接收的读数。
将以下代码上传到您的接收板 - 该代码已准备好接收来自两个不同板的读数。
#include <espnow.h>
#include <ESP8266WiFi.h>
#include "ESPAsyncWebServer.h"
#include "ESPAsyncTCP.h"
#include <Arduino_JSON.h>// Replace with your network credentials (STATION)
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";// Structure example to receive data
// Must match the sender structure
typedef struct struct_message {int id;float temp;float hum;unsigned int readingId;
} struct_message;struct_message incomingReadings;JSONVar board;AsyncWebServer server(80);
AsyncEventSource events("/events");// callback function that will be executed when data is received
void OnDataRecv(uint8_t * mac_addr, uint8_t *incomingData, uint8_t len) { // Copies the sender mac address to a stringchar macStr[18];Serial.print("Packet received from: ");snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);Serial.println(macStr);memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));board["id"] = incomingReadings.id;board["temperature"] = incomingReadings.temp;board["humidity"] = incomingReadings.hum;board["readingId"] = String(incomingReadings.readingId);String jsonString = JSON.stringify(board);events.send(jsonString.c_str(), "new_readings", millis());Serial.printf("Board ID %u: %u bytes\n", incomingReadings.id, len);Serial.printf("t value: %4.2f \n", incomingReadings.temp);Serial.printf("h value: %4.2f \n", incomingReadings.hum);Serial.printf("readingID value: %d \n", incomingReadings.readingId);Serial.println();
}const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head><title>ESP-NOW DASHBOARD</title><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous"><link rel="icon" href="data:,"><style>html {font-family: Arial; display: inline-block; text-align: center;}h1 { font-size: 2rem;}body { margin: 0;}.topnav { overflow: hidden; background-color: #2f4468; color: white; font-size: 1.7rem; }.content { padding: 20px; }.card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }.cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }.reading { font-size: 2.8rem; }.timestamp { color: #bebebe; font-size: 1rem; }.card-title{ font-size: 1.2rem; font-weight : bold; }.card.temperature { color: #B10F2E; }.card.humidity { color: #50B8B4; }</style>
</head>
<body><div class="topnav"><h1>ESP-NOW DASHBOARD</h1></div><div class="content"><div class="cards"><div class="card temperature"><p class="card-title"><i class="fas fa-thermometer-half"></i> BOARD #1 - TEMPERATURE</p><p><span class="reading"><span id="t1"></span> °C</span></p><p class="timestamp">Last Reading: <span id="rt1"></span></p></div><div class="card humidity"><p class="card-title"><i class="fas fa-tint"></i> BOARD #1 - HUMIDITY</p><p><span class="reading"><span id="h1"></span> %</span></p><p class="timestamp">Last Reading: <span id="rh1"></span></p></div><div class="card temperature"><p class="card-title"><i class="fas fa-thermometer-half"></i> BOARD #2 - TEMPERATURE</p><p><span class="reading"><span id="t2"></span> °C</span></p><p class="timestamp">Last Reading: <span id="rt2"></span></p></div><div class="card humidity"><p class="card-title"><i class="fas fa-tint"></i> BOARD #2 - HUMIDITY</p><p><span class="reading"><span id="h2"></span> %</span></p><p class="timestamp">Last Reading: <span id="rh2"></span></p></div></div></div>
<script>
function getDateTime() {var currentdate = new Date();var datetime = currentdate.getDate() + "/"+ (currentdate.getMonth()+1) + "/"+ currentdate.getFullYear() + " at "+ currentdate.getHours() + ":"+ currentdate.getMinutes() + ":"+ currentdate.getSeconds();return datetime;
}
if (!!window.EventSource) {var source = new EventSource('/events');source.addEventListener('open', function(e) {console.log("Events Connected");}, false);source.addEventListener('error', function(e) {if (e.target.readyState != EventSource.OPEN) {console.log("Events Disconnected");}}, false);source.addEventListener('message', function(e) {console.log("message", e.data);}, false);source.addEventListener('new_readings', function(e) {console.log("new_readings", e.data);var obj = JSON.parse(e.data);document.getElementById("t"+obj.id).innerHTML = obj.temperature.toFixed(2);document.getElementById("h"+obj.id).innerHTML = obj.humidity.toFixed(2);document.getElementById("rt"+obj.id).innerHTML = getDateTime();document.getElementById("rh"+obj.id).innerHTML = getDateTime();}, false);
}
</script>
</body>
</html>)rawliteral";void setup() {// Initialize Serial MonitorSerial.begin(115200);// Set the device as a Station and Soft Access Point simultaneouslyWiFi.mode(WIFI_AP_STA);// Set device as a Wi-Fi StationWiFi.begin(ssid, password);while (WiFi.status() != WL_CONNECTED) {delay(1000);Serial.println("Setting as a Wi-Fi Station..");}Serial.print("Station IP Address: ");Serial.println(WiFi.localIP());Serial.print("Wi-Fi Channel: ");Serial.println(WiFi.channel());// Init ESP-NOWif (esp_now_init() != 0) {Serial.println("Error initializing ESP-NOW");return;}// Once ESPNow is successfully Init, we will register for recv CB to// get recv packer infoesp_now_register_recv_cb(OnDataRecv);server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){request->send_P(200, "text/html", index_html);});events.onConnect([](AsyncEventSourceClient *client){if(client->lastId()){Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());}// send event with message "hello!", id current millis// and set reconnect delay to 1 secondclient->send("hello!", NULL, millis(), 10000);});server.addHandler(&events);server.begin();
}void loop() {static unsigned long lastEventTime = millis();static const unsigned long EVENT_INTERVAL_MS = 5000;if ((millis() - lastEventTime) > EVENT_INTERVAL_MS) {events.send("ping",NULL,millis());lastEventTime = millis();}
}
代码如何工作
首先,包括必要的库。
#include <espnow.h>
#include <ESP8266WiFi.h>
#include "ESPAsyncWebServer.h"
#include "ESPAsyncTCP.h"
#include <Arduino_JSON.h>
这Arduino_JSON库是必需的,因为我们将使用从每个板接收到的数据创建一个 JSON 变量。这个 JSON 变量将用于将所有需要的信息发送到网页,您将在本项目的后面看到。 在以下行中插入您的网络凭据,以便 ESP8266 可以连接到您的本地网络。
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
数据结构
然后,创建一个包含我们将接收的数据的结构。我们称这种结构结构消息它包含电路板 ID、温度和湿度读数以及读数 ID。
typedef struct struct_message {int id;float temp;float hum;int readingId;
} struct_message;
创建一个新的类型变量结构消息它被称作传入读数这将存储变量值。
struct_message incomingReadings;
创建一个名为board.
JSONVar board;
在端口 80 上创建异步 Web 服务器。
AsyncWebServer server(80);
创建事件源
要在新读数到达时自动在 Web 服务器上显示信息,我们将使用服务器发送事件 (SSE)。
下面一行创建了一个新的事件源。
AsyncEventSource events("/events");
服务器发送事件允许网页(客户端)从服务器获取更新。当新的 ESP-NOW 数据包到达时,我们将使用它在 Web 服务器页面上自动显示新读数。
OnDataRecv() 函数
这OnDataRecv()当您收到新的 ESP-NOW 数据包时,函数将被执行。
void OnDataRecv(uint8_t * mac_addr, uint8_t *incomingData, uint8_t len) {
在该函数内,打印发件人的 MAC 地址:
char macStr[18];
Serial.print("Packet received from: ");
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
Serial.println(macStr);
复制里面的信息输入数据变量传入读数结构变量。
memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));
然后,使用接收到的信息创建一个 JSON 字符串变量 :
board["id"] = incomingReadings.id;
board["temperature"] = incomingReadings.temp;
board["humidity"] = incomingReadings.hum;
board["readingId"] = String(incomingReadings.readingId);
String jsonString = JSON.stringify(board);
这是一个收到的json字符串
board = {"id": "1","temperature": "24.32","humidity" = "65.85","readingId" = "2"
}
在收集到所有接收到的json字符串变量数据后,将该信息作为事件发送到浏览器(“new_readings”)。
events.send(jsonString.c_str(), "new_readings", millis());
稍后,我们将看到如何在客户端处理这些事件。
最后,将接收到的信息打印到 Arduino IDE Serial Monitor 上进行调试:
Serial.printf("Board ID %u: %u bytes\n", incomingReadings.id, len);
Serial.printf("t value: %4.2f \n", incomingReadings.temp);
Serial.printf("h value: %4.2f \n", incomingReadings.hum);
Serial.printf("readingID value: %d \n", incomingReadings.readingId);
Serial.println();
构建网页
这index_html变量包含构建网页的所有 HTML、CSS 和 JavaScript。我不会详细介绍 HTML 和 CSS 的工作原理。我们只看一下如何处理服务器发送的事件。
处理事件
创建一个新的事件源对象并指定发送更新的页面的 URL。在我们的例子中它是事件源。
if (!!window.EventSource) {var source = new EventSource('/events');
一旦你实例化了一个事件源,你就可以开始监听来自服务器的消息了添加事件监听器().
这些是默认的事件侦听器,如 AsyncWebServer文档中所示。
source.addEventListener('open', function(e) {console.log("Events Connected");
}, false);
source.addEventListener('error', function(e) {if (e.target.readyState != EventSource.OPEN) {console.log("Events Disconnected");}
}, false);source.addEventListener('message', function(e) {console.log("message", e.data);
}, false);
然后,添加事件侦听器“new_readings”。
source.addEventListener('new_readings', function(e) {
当 ESP8266 收到一个新数据包时,它会发送一个带有读数的 JSON 字符串作为事件(“new_readings”) 给客户。以下几行处理浏览器收到该事件时发生的情况。
console.log("new_readings", e.data);
var obj = JSON.parse(e.data);
document.getElementById("t"+obj.id).innerHTML = obj.temperature.toFixed(2);
document.getElementById("h"+obj.id).innerHTML = obj.humidity.toFixed(2);
document.getElementById("rt"+obj.id).innerHTML = getDateTime();
document.getElementById("rh"+obj.id).innerHTML = getDateTime();
基本上就是在浏览器控制台打印新的读数,把接收到的数据放到网页上对应id的元素中。我们还通过致电更新接收读数的日期和时间获取日期时间()JavaScript 函数。
function getDateTime() {var currentdate = new Date();var datetime = currentdate.getDate() + "/"+ (currentdate.getMonth()+1) + "/"+ currentdate.getFullYear() + " at "+ currentdate.getHours() + ":"+ currentdate.getMinutes() + ":"+ currentdate.getSeconds();return datetime;
}
setup()
在里面setup(), 将 ESP8266 接收器设置为接入点和 Wi-Fi 站:
WiFi.mode(WIFI_AP_STA);
以下行将 ESP8266 连接到您的本地网络并打印 IP 地址和 Wi-Fi 信道:
// Set device as a Wi-Fi Station
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {delay(1000);Serial.println("Setting as a Wi-Fi Station..");
}
Serial.print("Station IP Address: ");
Serial.println(WiFi.localIP());
Serial.print("Wi-Fi Channel: ");
Serial.println(WiFi.channel());
初始化 ESP-NOW。
if (esp_now_init() != 0) {Serial.println("Error initializing ESP-NOW");return;
}
注册数据接收回调函数,以便在新的 ESP-NOW 数据包到达时执行。
esp_now_register_recv_cb(OnDataRecv);
处理请求
当你在root上访问ESP8266的IP地址/URL,发送存储在index_html构建网页的变量。
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){request->send_P(200, "text/html", index_html);
});
服务器事件源
在服务器上设置事件源。
events.onConnect([](AsyncEventSourceClient *client){if(client->lastId()){Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());}// send event with message "hello!", id current millis// and set reconnect delay to 1 secondclient->send("hello!", NULL, millis(), 10000);
);
server.addHandler(&events);
最后,启动服务器。
server.begin();
loop()
在里面loop(),每 5 秒发送一次 ping。这用于在客户端检查服务器是否仍在运行(这段代码不是强制性的)。
static unsigned long lastEventTime = millis();
static const unsigned long EVENT_INTERVAL_MS = 5000;
if ((millis() - lastEventTime) > EVENT_INTERVAL_MS) {events.send("ping",NULL,millis());lastEventTime = millis();
}
下图总结了服务器发送的事件如何在此项目上工作,以及它如何在不刷新网页的情况下更新值。
将代码上传到接收板后,按下板载 EN/RST 按钮。ESP8266 的 IP 地址应该打印在串行监视器和 Wi-Fi 通道上。
ESP8266 硬件的连接
ESP8266 开发板连接到 BME280 传感器。将传感器连接到默认的 ESP8266 I2C 引脚:
- 接口 5(D1) -> SCL
- 接口 4(D2) -> SDA
ESP8266 采集板代码 (ESP-NOW)
每个采集板将数据通过 ESP-NOW协议发送一个JSON,其中包含采集板 ID(以便您可以识别哪个板发送了读数)、温度、湿度和读数 ID。阅读 ID 是一个 int 数字,可以知道发送了多少条消息。
将以下代码上传到您的每个采集板上,不要忘记增加 ID 到每个发送板的编号,修改WIFI账号和密码信息。
/*Rui SantosComplete project details at https://RandomNerdTutorials.com/esp8266-esp-now-wi-fi-web-server/Permission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files.The above copyright notice and this permission notice shall be included in allcopies or substantial portions of the Software.
*/#include <espnow.h>
#include <ESP8266WiFi.h>
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>// Set your Board ID (ESP32 Sender #1 = BOARD_ID 1, ESP32 Sender #2 = BOARD_ID 2, etc)
#define BOARD_ID 2Adafruit_BME280 bme; //MAC Address of the receiver
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};//Structure example to send data
//Must match the receiver structure
typedef struct struct_message {int id;float temp;float hum;int readingId;
} struct_message;//Create a struct_message called myData
struct_message myData;unsigned long previousMillis = 0; // Stores last time temperature was published
const long interval = 10000; // Interval at which to publish sensor readingsunsigned int readingId = 0;// Insert your SSID
constexpr char WIFI_SSID[] = "REPLACE_WITH_YOUR_SSID";int32_t getWiFiChannel(const char *ssid) {if (int32_t n = WiFi.scanNetworks()) {for (uint8_t i=0; i<n; i++) {if (!strcmp(ssid, WiFi.SSID(i).c_str())) {return WiFi.channel(i);}}}return 0;
}void initBME(){if (!bme.begin(0x76)) {Serial.println("Could not find a valid BME280 sensor, check wiring!");while (1);}
}float readTemperature() {float t = bme.readTemperature();return t;
}float readHumidity() {float h = bme.readHumidity();return h;
}// Callback when data is sent
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {Serial.print("Last Packet Send Status: ");if (sendStatus == 0){Serial.println("Delivery success");}else{Serial.println("Delivery fail");}
}void setup() {//Init Serial MonitorSerial.begin(115200);initBME(); // Set device as a Wi-Fi Station and set channelWiFi.mode(WIFI_STA);int32_t channel = getWiFiChannel(WIFI_SSID);WiFi.printDiag(Serial); // Uncomment to verify channel number beforewifi_promiscuous_enable(1);wifi_set_channel(channel);wifi_promiscuous_enable(0);WiFi.printDiag(Serial); // Uncomment to verify channel change after// Init ESP-NOWif (esp_now_init() != 0) {Serial.println("Error initializing ESP-NOW");return;}// Once ESPNow is successfully Init, we will register for Send CB to// get the status of Trasnmitted packetesp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);esp_now_register_send_cb(OnDataSent);esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);
}void loop() {unsigned long currentMillis = millis();if (currentMillis - previousMillis >= interval) {// Save the last time a new reading was publishedpreviousMillis = currentMillis;//Set values to sendmyData.id = BOARD_ID;myData.temp = readTemperature();myData.hum = readHumidity();myData.readingId = readingId++;esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));Serial.print("loop");}
}
代码如何工作
首先导入所需的库:
#include <espnow.h>
#include <ESP8266WiFi.h>
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
设置板号
定义ESP8266采集板ID,例如setBOARD_ID 1对于 ESP8266 Sender #1,等等……
#define BOARD_ID 1
BME280 传感器
创建一个Adafruit_BME280称为对象bme。
Adafruit_BME280 bme;
接收者的 MAC 地址
在下一行插入接收方的 MAC 地址(例如):
uint8_t broadcastAddress[] = {0x30, 0xAE, 0xA4, 0x15, 0xC7, 0xFC};
数据结构
然后,创建一个包含我们要发送的数据的结构。这结构消息包含电路板 ID、温度读数、湿度读数和读数 ID。
typedef struct struct_message {int id;float temp;float hum;int readingId;
} struct_message;
创建一个新的类型变量结构消息它被称作我的资料存储变量的值。
struct_message myData;
定时器间隔
创建一些辅助计时器变量以每 10 秒发布一次读数。您可以更改延迟时间间隔多变的。
unsigned long previousMillis = 0; // Stores last time temperature was published
const long interval = 10000; // Interval at which to publish sensor readings
初始化阅读编号变量——它跟踪发送的读数数量。
unsigned int readingId = 0;
更改 Wi-Fi 频道
现在,我们将获取接收器的 Wi-Fi 信道。这很有用,因为它允许我们自动将相同的 Wi-Fi 通道分配给采集板。
为此,您必须在以下行中插入您的 SSID:
constexpr char WIFI_SSID[] = "REPLACE_WITH_YOUR_SSID";
然后,getWiFiChannel()函数扫描您的网络并获取其频道。
int32_t getWiFiChannel(const char *ssid) {if (int32_t n = WiFi.scanNetworks()) {for (uint8_t i=0; i<n; i++) {if (!strcmp(ssid, WiFi.SSID(i).c_str())) {return WiFi.channel(i);}}}return 0;
}
初始化 BME280 传感器
这initBME()函数初始化 BME280 传感器。
void initBME(){if (!bme.begin(0x76)) {Serial.println("Could not find a valid BME280 sensor, check wiring!");while (1);}
}
读数温度
这readTemperature()函数读取并返回 BME280 传感器的温度。
float readTemperature() {float t = bme.readTemperature();return t;
}
读数湿度
这readHumidity()函数读取并返回来自 BME280 传感器的湿度。
float readHumidity() {float h = bme.readHumidity();return h;
}
OnDataSent 回调函数
这OnDataSent ()发送消息时将执行回调函数。在这种情况下,此函数会打印消息是否已成功传递。
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {Serial.print("Last Packet Send Status: ");if (sendStatus == 0){Serial.println("Delivery success");}else{Serial.println("Delivery fail");}
}
setu()
初始化串行监视器。
Serial.begin(115200);
初始化 BME280 传感器:
initBME();
将 ESP8266 设置为 Wi-Fi 站点。
WiFi.mode(WIFI_STA);
设置其频道以匹配接收器的 Wi-Fi 频道:
int32_t channel = getWiFiChannel(WIFI_SSID);WiFi.printDiag(Serial); // Uncomment to verify channel number before
wifi_promiscuous_enable(1);
wifi_set_channel(channel);
wifi_promiscuous_enable(0);
WiFi.printDiag(Serial); // Uncomment to verify channel change after
初始化 ESP-NOW。
// Init ESP-NOW
if (esp_now_init() != 0) {Serial.println("Error initializing ESP-NOW");return;
}
设置 ESP8266 角色:
esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
成功初始化 ESP-NOW 后,注册发送消息时调用的回调函数。在这种情况下,注册OnDataSent()之前创建的函数。
esp_now_register_send_cb(OnDataSent);
添加同行
要将数据发送到另一块板(接收器),您需要将其配对为对等体。以下代码将注册接收方并添加为对等方。
esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);
loop()
在里面loop(), 检查是否到了获取和发送新读数的时间。
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {// Save the last time a new reading was publishedpreviousMillis = currentMillis;
发送 ESP-NOW 消息
最后,通过 ESP-NOW 发送消息结构。
esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
将代码上传到您的采集板上。您应该注意到采集板将其 Wi-Fi 通道更改为接收板的通道。
示范
将代码上传到所有采集板后,如果一切按预期进行,ESP8266接收板应该开始从其他采集板接收传感器数据。
在本地网络上打开浏览器并输入 ESP8266 的 IP 地址。
它应该加载温度、湿度和最后一次在网页上为每块采集板更新读数的时间。收到新数据包后,您的网页会自动更新而无需刷新网页。
总结
在本教程中,您学习了如何使用 ESP-NOW 和 Wi-Fi 设置 Web 服务器以使用 ESP8266 NodeMCU 板从多个板(多对一配置)接收 ESP-NOW 数据包。
此外,您还使用服务器发送事件在每次收到新数据包时自动更新网页,而无需刷新网页。
ESP8266 NodeMCU:ESP-NOW Web 服务器传感器仪表板(ESP-NOW + Wi-Fi)相关推荐
- ESP8266 NodeMCU Web 服务器:在仪表盘中显示传感器读数
了解如何使用 ESP8266 NodeMCU 构建网络服务器以在仪表盘中显示传感器读数.例如,我们将以两种不同的仪表显示 BME280 传感器的温度和湿度:线性和径向.您可以轻松修改项目以绘制任何其他 ...
- ESP8266/ESP32 网络温控器监控 Web服务器-基于温度控制输出
ESP8266/ESP32 网络温控器监控 Web服务器-基于温度控制输出 示意图 接线图 实例代码 #ifdef ESP32#include <WiFi.h>#include & ...
- nodemcu 自建服务器,NodeMCU入门(4):搭建Web服务器,配置网络连接(示例代码)
准备工作 1.NodeMCU模块 2.ESPlorer v0.2.0-rc6 3.NodeMCU-HTTP-Server 搭建web服务器 修改init.lua文件,可参看NodeMCU-HTTP-S ...
- esp虚拟服务器,esp32搭建web服务器
esp32搭建web服务器 内容精选 换一换 云解析服务支持为域名快速添加网站解析,通过该功能可以简化解析记录的配置,包含如下两种场景:网站解析至IP地址:为域名的主域名和子域名分别添加一条A类型记录 ...
- esp8266 nodemcu 自制mp3
ESP8266 播放 mp3 其实早就想做一个mp3播放器,但是一直没有时间,借着这次高考周放假,可以开始自己的开发. 准备工作 购置需要用到的模块 ESP8266 Nodemcu 作为开发板 OLE ...
- ESP32 / ESP8266实时图表中的绘图传感器读数
了解如何使用带Arduino IDE的ESP32或ESP8266在Web服务器上绘制传感器读数(温度,湿度和压力). ESP将托管一个包含三个实时图表的网页,该图表每30秒添加一次新读数. 项目概述 ...
- 简单明了操作——ESP8266 NodeMCU驱动TFT LCD液晶屏(制作透明小电视前奏)
简单明了操作--ESP8266 NodeMCU驱动TFT LCD液晶屏(制作透明小电视前奏) 前言 准备材料 esp8266 NodeMCU(串口WiFi模块) 1.44inch SPI Arduin ...
- Esp8266(NodeMcu)接入新大陆物联网平台并且上传温湿度
Esp8266[NodeMcu]接入新大陆物联网 1.平台注册和产品创建 2.代码协议部分2.1 连接请求协议:2.2 数据上报部分协议 3.完整代码部分 3.1 效果图: 使用Esp8266接入新大 ...
- Esp8266 nodemcu 使用PubSubClient连接阿里云物联网平台
之前写了一篇微信小程序使用MQTT.js连接阿里云IoT物联网平台,然后很多人问问题的时候顺带会问些硬件的问题,但是自己不会,没法回答.最近有些空闲的时间,自己也挺感兴趣,于是花了一个星期左右的时间看 ...
最新文章
- CentOS7—HAProxy安装与配置
- python连连看小游戏_请用PYTHON编一个小游戏,如五子棋,连连看,贪吃蛇,扫雷,计算器等等...
- freemaker if 多个条件_第4天|14天搞定Vue3.0,条件渲染和template
- 兰州市中考会考计算机考试,2016兰州中考体育26日开考 采用全套智能测试仪器...
- 【jquery】find() 方法,filter()方法和children()方法
- UVA - 247 Calling Circles(Floyd求传递闭包)
- java 获取密码框密码,获得Windows下的密码框密码--编程学习网
- Struts2 Jakarta远程执行代码测试
- 小乌龟与git配置使用
- Android实战简易教程-第七十三枪(拨打、接听电话自动免提)
- 非好友怎么进qq权限空间
- 携程机票数据仓库建设之路
- WEB入门.七 	CSS布局模型
- 计算机国际期刊等级,计算机期刊等级(全)
- UVa 10105 - Polynomial Coefficients
- 尝遍裸辞各种苦,再也不敢任性裸辞了!
- 四、 按键控制流水灯的运行与暂停
- 电话簿程序设计c语言,电话簿管理程序设计.doc
- Google Chrome误删书签的恢复方式!
- 使用C# 创建windows 服务