在本项目中,您将学习如何使用 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> &deg;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> &percnt;</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> &deg;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> &percnt;</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)相关推荐

  1. ESP8266 NodeMCU Web 服务器:在仪表盘中显示传感器读数

    了解如何使用 ESP8266 NodeMCU 构建网络服务器以在仪表盘中显示传感器读数.例如,我们将以两种不同的仪表显示 BME280 传感器的温度和湿度:线性和径向.您可以轻松修改项目以绘制任何其他 ...

  2. ESP8266/ESP32 网络温控器监控 Web服务器-基于温度控制输出

    ESP8266/ESP32 网络温控器监控 Web服务器-基于温度控制输出 示意图 接线图 实例代码 #ifdef ESP32#include <WiFi.h>#include & ...

  3. nodemcu 自建服务器,NodeMCU入门(4):搭建Web服务器,配置网络连接(示例代码)

    准备工作 1.NodeMCU模块 2.ESPlorer v0.2.0-rc6 3.NodeMCU-HTTP-Server 搭建web服务器 修改init.lua文件,可参看NodeMCU-HTTP-S ...

  4. esp虚拟服务器,esp32搭建web服务器

    esp32搭建web服务器 内容精选 换一换 云解析服务支持为域名快速添加网站解析,通过该功能可以简化解析记录的配置,包含如下两种场景:网站解析至IP地址:为域名的主域名和子域名分别添加一条A类型记录 ...

  5. esp8266 nodemcu 自制mp3

    ESP8266 播放 mp3 其实早就想做一个mp3播放器,但是一直没有时间,借着这次高考周放假,可以开始自己的开发. 准备工作 购置需要用到的模块 ESP8266 Nodemcu 作为开发板 OLE ...

  6. ESP32 / ESP8266实时图表中的绘图传感器读数

    了解如何使用带Arduino IDE的ESP32或ESP8266在Web服务器上绘制传感器读数(温度,湿度和压力). ESP将托管一个包含三个实时图表的网页,该图表每30秒添加一次新读数. 项目概述 ...

  7. 简单明了操作——ESP8266 NodeMCU驱动TFT LCD液晶屏(制作透明小电视前奏)

    简单明了操作--ESP8266 NodeMCU驱动TFT LCD液晶屏(制作透明小电视前奏) 前言 准备材料 esp8266 NodeMCU(串口WiFi模块) 1.44inch SPI Arduin ...

  8. Esp8266(NodeMcu)接入新大陆物联网平台并且上传温湿度

    Esp8266[NodeMcu]接入新大陆物联网 1.平台注册和产品创建 2.代码协议部分2.1 连接请求协议:2.2 数据上报部分协议 3.完整代码部分 3.1 效果图: 使用Esp8266接入新大 ...

  9. Esp8266 nodemcu 使用PubSubClient连接阿里云物联网平台

    之前写了一篇微信小程序使用MQTT.js连接阿里云IoT物联网平台,然后很多人问问题的时候顺带会问些硬件的问题,但是自己不会,没法回答.最近有些空闲的时间,自己也挺感兴趣,于是花了一个星期左右的时间看 ...

最新文章

  1. CentOS7—HAProxy安装与配置
  2. python连连看小游戏_请用PYTHON编一个小游戏,如五子棋,连连看,贪吃蛇,扫雷,计算器等等...
  3. freemaker if 多个条件_第4天|14天搞定Vue3.0,条件渲染和template
  4. 兰州市中考会考计算机考试,2016兰州中考体育26日开考 采用全套智能测试仪器...
  5. 【jquery】find() 方法,filter()方法和children()方法
  6. UVA - 247 Calling Circles(Floyd求传递闭包)
  7. java 获取密码框密码,获得Windows下的密码框密码--编程学习网
  8. Struts2 Jakarta远程执行代码测试
  9. 小乌龟与git配置使用
  10. Android实战简易教程-第七十三枪(拨打、接听电话自动免提)
  11. 非好友怎么进qq权限空间
  12. 携程机票数据仓库建设之路
  13. WEB入门.七 CSS布局模型
  14. 计算机国际期刊等级,计算机期刊等级(全)
  15. UVa 10105 - Polynomial Coefficients
  16. 尝遍裸辞各种苦,再也不敢任性裸辞了!
  17. 四、 按键控制流水灯的运行与暂停
  18. 电话簿程序设计c语言,电话簿管理程序设计.doc
  19. Google Chrome误删书签的恢复方式!
  20. 使用C# 创建windows 服务

热门文章

  1. MongoDB在58同城的应用实践
  2. 使用OpenSSL实现CA证书的搭建过程
  3. 全局最优和局部最优 世俗理解以及原理解释
  4. 数据分析师python面试题_数据分析师面试题
  5. 各种插入函数收集整理
  6. Ubuntu设为桥接模式自动获取ip但无法上网
  7. PDF合并:如何将两个PDF文件合并成一个PDF文件
  8. 山东大学人工智能专业认知科学与类脑计算回忆版
  9. oracle添加序列
  10. 多时间尺度源储荷微电网协调调度+日前日内实时+需求响应——附代码