ESP8266 NodeMCU: ESP-NOW Web Server Sensor Dashboard (ESP-NOW + Wi-Fi)

In this project, you will learn how to use the ESP8266 NodeMCU board to host a web server while using the ESP-NOW communication protocol. You can have multiple ESP8266 boards send sensor readings via ESP-NOW to one ESP8266 receiver, which displays all readings on a web server. The software code is programmed using the Arduino IDE.

Use ESP-NOW and Wi-Fi simultaneously

If you want to use Wi-Fi to host a web server and also use ESP-NOW to receive sensor readings from other boards, there are a few things to consider:

  • The ESP8266 sending board must use the same Wi-Fi channel as the receiving board.
  • The receiving board's Wi-Fi channel is automatically assigned by your Wi-Fi router.
  • The Wi-Fi mode of the receiving board must be Access Point and Station ( WIFI_AP_STA ).
  • You can manually set the same Wi-Fi channel, or you can add simple code on the transmitter to set its Wi-Fi channel to the same Wi-Fi channel as the receiving board.

Project Overview

The image below shows an overview of the project we will build.

  • There are two ESP8266 sending boards, which send BME280 temperature and humidity readings to one ESP8266 receiving board through ESP-NOW (ESP-NOW many-to-one configuration);
  • The ESP8266 receiving board receives the packets and displays the readings on the web server;
  • The web page is automatically updated every time a new reading is received using Server Sent Events (SSE).
  • The page also displays the last time the reading was updated using JavaScript.

Prerequisites

Before proceeding with this project, be sure to check the following prerequisites.

development environment

We will be using the Arduino IDE to program the ESP8266 board, so before continuing with this tutorial, make sure you have the ESP8266 board installed in your Arduino IDE.

  • Install the ESP8266 development board in the Arduino IDE (Windows, Mac OS X and Linux)

BME280 Library

The ESP8266 sending board will send temperature and humidity readings from the BME280 sensor.

To read data from the BME280 sensor we will use the Adafruit_BME280 library . To use this library, you also need to install  the Adafruit Unified Sensor library . Follow the next steps to install these libraries.

Search for " adafruit bme280 " in the search box    and install the library.

To use the BME280 library, you also need to install the Adafruit_Sensor library. Follow these steps to install the library in your Arduino IDE:

Go to  Sketch   >   Include Library   >   Manage Libraries  and type "  Adafruit Unified Sensor" in the search box. Scroll all the way down to find the library and install it.

To learn more about the BME280 temperature, humidity and pressure sensor, read our guide: ESP8266 and BME280 using the Arduino IDE (Pressure, Temperature, Humidity).

Asynchronous web server library

To build a web server, you need to install the following libraries:

These libraries cannot be installed through the Arduino Library Manager, so you need to copy the library files to the Arduino Installation Libraries folder. Alternatively, in your Arduino IDE you can go to  Sketch   >   Include Library   >   Add .zip Library  and select the library you just downloaded.

Arduino_JSON library

You need to install the Arduino_JSON library. You can install this library in the Arduino IDE library manager. Just go to  Sketch   >   Include Library   >   Manage Libraries  and search for the library name like this:

Required hardware

To follow this tutorial, you will need multiple ESP8266 development boards. We will use three ESP8266 boards. You also need:

  • 3x ESP8266 (read best ESP8266 development boards)
  • 2x BME280 Sensors – BME280 Guide for ESP8266
  • Breadboard
  • Jumper

Get the MAC address of the receiving board

To send messages via ESP-NOW, you need to know the receiving board. Each board has a unique MAC address.

Upload the following code to your ESP8266 receiving board to get its MAC address.

// 获取和更改ESP MAC地址的完整代码:

#ifdef ESP32
  #include <WiFi.h>
#else
  #include <ESP8266WiFi.h>
#endif

void setup(){
  Serial.begin(115200);
  Serial.println();
  Serial.print("ESP Board MAC Address:  ");
  Serial.println(WiFi.macAddress());
}
 
void loop(){

}

After uploading the code, press the RST/EN button and the MAC address should be displayed on the serial monitor.

ESP8266 Receiver (ESP-NOW + Web Server)

The ESP8266 NodeMCU receiving board receives packets from the sending board and hosts a web server to display the latest received readings.

Upload the following code to your receiving board - This code is ready to receive readings from two different boards.

#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 string
  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));
  
  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 Monitor
  Serial.begin(115200);

  // Set the device as a Station and Soft Access Point simultaneously
  WiFi.mode(WIFI_AP_STA);
  
  // 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());

  // Init ESP-NOW
  if (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 info
  esp_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 second
    client->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();
  }
}

How the code works

First, include the necessary libraries.

#include <espnow.h>
#include <ESP8266WiFi.h>
#include "ESPAsyncWebServer.h"
#include "ESPAsyncTCP.h"
#include <Arduino_JSON.h>

The Arduino_JSON library is required because we will create a JSON variable using the data received from each board. This JSON variable will be used to send all the required information to the web page, as you will see later in this project. Insert your network credentials in the following lines so the ESP8266 can connect to your local network.

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

data structure

Then, create a structure that contains the data we will receive. We call this structure message which contains the board ID, temperature and humidity readings, and the reading ID.

typedef struct struct_message {
    int id;
    float temp;
    float hum;
    int readingId;
} struct_message;

Create a new variable structure of type message it is called incoming reading this will store the variable value.

struct_message incomingReadings;

Create a file called board.

JSONVar board;

Create an asynchronous web server on port 80.

AsyncWebServer server(80);

Create event source

To automatically display information on the web server when new readings arrive, we will use Server Sent Events (SSE).

The following line creates a new event source.

AsyncEventSource events("/events");

Server-sent events allow a web page (client) to get updates from the server. We will use this to automatically display new readings on the web server page when a new ESP-NOW packet arrives.

OnDataRecv() function

This OnDataRecv() function will be executed when you receive a new ESP-NOW packet .

void OnDataRecv(uint8_t * mac_addr, uint8_t *incomingData, uint8_t len) { 

Within this function, print the sender's MAC address:

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);

Copy the information inside the input data variable and pass it into the reading structure variable.

memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));

Then, create a JSON string variable using the received information:

board["id"] = incomingReadings.id;
board["temperature"] = incomingReadings.temp;
board["humidity"] = incomingReadings.hum;
board["readingId"] = String(incomingReadings.readingId);
String jsonString = JSON.stringify(board);

This is a json string received

board = {
  "id": "1",
  "temperature": "24.32",
  "humidity" = "65.85",
  "readingId" = "2"
}

After collecting all received json string variable data, send this information to the browser as an event ( "new_readings" ).

events.send(jsonString.c_str(), "new_readings", millis());

Later, we will see how to handle these events on the client side.

Finally, print the received information to the Arduino IDE Serial Monitor for debugging:

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();

Build a web page

The index_html variable contains all the HTML, CSS, and JavaScript that build the web page. I won't go into detail about how HTML and CSS work. We'll just look at how to handle server-sent events.

handle events

Create a new event source object and specify the URL of the page to send updates to. In our case it is the event source.

if (!!window.EventSource) {
  var source = new EventSource('/events');

Once you have instantiated an event source, you can start listening for messages from the server by adding eventListener() .

These are the default event listeners as shown in the AsyncWebServer documentation .

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);

Then, add the event listener "new_readings".

source.addEventListener('new_readings', function(e) {
   
   

When ESP8266 receives a new packet, it sends a JSON string with the readings as an event ( “new_readings” ) to the client. The following lines handle what happens when the browser receives this event.

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();

Basically, it prints new readings in the browser console and puts the received data into the element corresponding to the id on the web page. We also update the date and time the reading was received by calling the GetDateTime() JavaScript function.

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()

Inside setup() , set up the ESP8266 receiver as an access point and Wi-Fi station:

WiFi.mode(WIFI_AP_STA);

The following lines connect the ESP8266 to your local network and print the IP address and Wi-Fi channel:

// 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());

Initialize ESP-NOW.

if (esp_now_init() != 0) {
  Serial.println("Error initializing ESP-NOW");
  return;
}

Register the data receive callback function to execute when a new ESP-NOW packet arrives.

esp_now_register_recv_cb(OnDataRecv);

Handle request

When you access the ESP8266's IP address / URL as root , send the variables stored in index_html to build the web page.

server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send_P(200, "text/html", index_html);
});

Server event source

Set up the event source on the server.

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 second
  client->send("hello!", NULL, millis(), 10000);
);
server.addHandler(&events);

Finally, start the server.

server.begin();

loop()

Inside loop() , a ping is sent every 5 seconds. This is used on the client side to check if the server is still running (this code is not mandatory).

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();
}

The image below summarizes how server-sent events work on this project and how it updates values ​​without refreshing the web page.

After uploading the code to the receiving board, press the onboard EN/RST button. The IP address of the ESP8266 should be printed on the serial monitor and Wi-Fi channel.

ESP8266 hardware connection

The ESP8266 development board is connected to the BME280 sensor. Connect the sensor to the default ESP8266 I2C pins:

  • Interface 5 (D1) -> SCL
  • Port 4 (D2) -> SDA

ESP8266 acquisition board code (ESP-NOW)

Each acquisition board sends data via the ESP-NOW protocol as a JSON that contains the acquisition board ID (so you can identify which board sent the reading), temperature, humidity, and reading ID. The reading ID is an int number that tells how many messages were sent.

Upload the following code to each of your collection boards. Don't forget to add  the ID  to the number of each sending board and modify the WIFI account and password information.

/*
  Rui Santos
  Complete 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 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.
*/

#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 2

Adafruit_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 readings

unsigned 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 Monitor
  Serial.begin(115200);
  initBME(); 

  // Set device as a Wi-Fi Station and set channel
  WiFi.mode(WIFI_STA);

  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

  // Init ESP-NOW
  if (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 packet
   esp_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 published
    previousMillis = currentMillis;
    //Set values to send
    myData.id = BOARD_ID;
    myData.temp = readTemperature();
    myData.hum = readHumidity();
    myData.readingId = readingId++;
     
    esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));

    Serial.print("loop");
  }
}

How the code works

First import the required libraries:

#include <espnow.h>
#include <ESP8266WiFi.h>
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>

Set board number

Define the ESP8266 acquisition board ID, for example set BOARD_ID 1 for ESP8266 Sender #1, etc...

#define BOARD_ID 1

BME280 sensor

Create an Adafruit_BME280 object called bme.

Adafruit_BME280 bme;

Receiver's MAC address

Insert the recipient's MAC address on the next line (for example):

uint8_t broadcastAddress[] = {0x30, 0xAE, 0xA4, 0x15, 0xC7, 0xFC};

data structure

Then, create a structure that contains the data we want to send. This structured message contains the board ID, temperature reading, humidity reading and reading ID.

typedef struct struct_message {
    int id;
    float temp;
    float hum;
    int readingId;
} struct_message;

Create a new type variable structure message which is called mydata to store the value of the variable.

struct_message myData;

timer interval

Create some auxiliary timer variables to publish readings every 10 seconds. You can change the delay interval to be variable.

unsigned long previousMillis = 0; // Stores last time temperature was published
const long interval = 10000; // Interval at which to publish sensor readings

Initialize the reading number variable - it keeps track of the number of readings sent.

unsigned int readingId = 0;

Change Wi-Fi channel

Now, we will get the Wi-Fi channel of the receiver. This is useful because it allows us to automatically assign the same Wi-Fi channel to the acquisition board.

To do this, you must insert your SSID in the following line:

constexpr char WIFI_SSID[] = "REPLACE_WITH_YOUR_SSID";

Then, the getWiFiChannel() function scans your network and gets its channel.

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;
}

Initialize BME280 sensor

This initBME() function initializes the BME280 sensor.

void initBME(){
  if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }
}

Reading temperature

The readTemperature() function reads and returns the temperature of the BME280 sensor.

float readTemperature() {
  float t = bme.readTemperature();
  return t;
}

Reading humidity

The readHumidity() function reads and returns the humidity from the BME280 sensor.

float readHumidity() {
  float h = bme.readHumidity();
  return h;
}

OnDataSent callback function

This OnDataSent() callback function will be executed when a message is sent. In this case, this function prints whether the message was successfully delivered.

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");
  }
}

set ( )

Initialize the serial monitor.

Serial.begin(115200);

Initialize the BME280 sensor:

initBME();

Set up ESP8266 as a Wi-Fi station.

WiFi.mode(WIFI_STA);

Set its channel to match the receiver's Wi-Fi channel:

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

Initialize ESP-NOW.

// Init ESP-NOW
if (esp_now_init() != 0) {
  Serial.println("Error initializing ESP-NOW");
  return;
}

Set ESP8266 role:

esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);

After successfully initializing ESP-NOW, register the callback function that is called when sending a message. In this case, register the OnDataSent() function you created before.

esp_now_register_send_cb(OnDataSent);

Add peers

To send data to another board (receiver) you need to pair it as a peer. The following code will register the receiver and add it as a peer.

esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);

loop()

Inside loop() , check if it's time to get and send a new reading.

unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
  // Save the last time a new reading was published
  previousMillis = currentMillis;

Send ESP-NOW message

Finally, the message structure is sent via ESP-NOW.

esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));

Upload the code to your acquisition board. You should notice that the acquisition board changes its Wi-Fi channel to that of the receiving board.

demonstration

After uploading the code to all acquisition boards, if everything goes as expected, the ESP8266 receiving board should start receiving sensor data from the other acquisition boards.

Open a browser on your local network and enter the IP address of the ESP8266. 

It should load the temperature, humidity, and the last time a reading was updated on the web page for each acquisition plate. Once a new packet is received, your web page will automatically update without the need to refresh the web page.

Summarize

In this tutorial, you learned how to set up a web server using ESP-NOW and Wi-Fi to receive ESP-NOW packets from multiple boards (many-to-one configuration) using the ESP8266 NodeMCU board.

Additionally, you use server-sent events to automatically update the web page every time a new packet is received, without having to refresh the web page.

Guess you like

Origin blog.csdn.net/hhqidi/article/details/130932161