In this project you’ll learn how to host a web server with the ESP8266 NodeMCU board and use ESP-NOW communication protocol at the same time. You can have several ESP8266 boards sending sensor readings via ESP-NOW to one ESP8266 receiver that displays all readings on a web server. The boards will be programmed using Arduino IDE.
We have other guides related to ESP-NOW that you might be interested in:
- Getting Started with ESP-NOW (ESP8266 NodeMCU with Arduino IDE)
- ESP-NOW Two-Way Communication Between ESP8266 NodeMCU Boards
- ESP-NOW with ESP8266: Send Data to Multiple Boards (one-to-many)
- ESP-NOW with ESP8266: Receive Data from Multiple Boards (many-to-one)
Using ESP-NOW and Wi-Fi Simultaneously
There are a few things you need to take into account if you want to use Wi-Fi to host a web server and use ESP-NOW simultaneously to receive sensor readings from other boards:
- The ESP8266 sender boards must use the same Wi-Fi channel of the receiver board.
- The Wi-Fi channel of the receiver board is automatically assigned by your Wi-Fi router.
- The Wi-Fi mode of the receiver board must be access point and station (WIFI_AP_STA).
- You can set up the same Wi-Fi channel manually, or you can add a simple spinet of code on the sender to set its Wi-Fi channel to the same of the receiver board.
Project Overview
The following diagram shows a high-level overview of the project we’ll build.
- There are two ESP8266 sender boards that send BME280 temperature and humidity readings via ESP-NOW to one ESP8266 receiver board (ESP-NOW many to one configuration);
- The ESP8266 receiver board receives the packets and displays the readings on a web server;
- The web page is updated automatically every time it receives a new reading using Server-Sent Events (SSE).
- The web page also shows the last time the readings were updated using JavaScript.
Prerequisites
Before proceeding with this project, make sure you check the following prerequisites.
Arduino IDE
We’ll program the ESP8266 boards using Arduino IDE, so before proceeding with this tutorial, make sure you have the ESP8266 board installed in your Arduino IDE.
BME280 Libraries
The ESP8266 sender board will send temperature and humidity readings from a BME280 sensor.
To read from the BME280 sensor, we’ll 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 those libraries.
Search for “adafruit bme280 ” on the Search box and install the library.
To use the BME280 library, you also need to install the Adafruit_Sensor library. Follow the next 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 with BME280 using Arduino IDE (Pressure, Temperature, Humidity).
Async Web Server Libraries
To build the web server you need to install the following libraries:
These libraries aren’t available to install 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 libraries you’ve 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 as follows:
Parts Required
To follow this tutorial, you need multiple ESP8266 boards. We’ll use three ESP8266 boards. You also need:
- 3x ESP8266 (read Best ESP8266 development boards)
- 2x BME280 sensor – BME280 guide for ESP8266
- Breadboard
- Jumper wires
You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!
Getting the Receiver Board MAC Address
To send messages via ESP-NOW, you need to know the receiver board’s MAC address. Each board has a unique MAC address (learn how to Get and Change the ESP8266 MAC Address).
Upload the following code to your ESP8266 receiver board to get its MAC address.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/get-change-esp32-esp8266-mac-address-arduino/
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.
*/
#ifdef ESP32
#include <WiFi.h>
#include <esp_wifi.h>
#else
#include <ESP8266WiFi.h>
#endif
void setup(){
Serial.begin(115200);
Serial.print("ESP Board MAC Address: ");
#ifdef ESP32
WiFi.mode(WIFI_STA);
WiFi.STA.begin();
uint8_t baseMac[6];
esp_err_t ret = esp_wifi_get_mac(WIFI_IF_STA, baseMac);
if (ret == ESP_OK) {
Serial.printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
baseMac[0], baseMac[1], baseMac[2],
baseMac[3], baseMac[4], baseMac[5]);
} else {
Serial.println("Failed to read MAC address");
}
#else
Serial.println(WiFi.macAddress());
#endif
}
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 receiver board receives the packets from the sender boards and hosts a web server to display the latest received readings.
Upload the following code to your receiver board – the code is prepared to receive readings from two different boards.
/*
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 "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> °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 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 needed because we’ll create a JSON variable with the data received from each board. This JSON variable will be used to send all the needed information to the web page as you’ll see later in this project.
Insert your network credentials on the following lines so that 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’ll receive. We called this structure struct_message and it 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 of type struct_message that is called incomingReadings that will store the variables values.
struct_message incomingReadings;
Create a JSON variable called board.
JSONVar board;
Create an Async Web Server on port 80.
AsyncWebServer server(80);
Create Event Source
To automatically display the information on the web server when a new reading arrives, we’ll use Server-Sent Events (SSE).
The following line creates a new event source on /events.
AsyncEventSource events("/events");
Server-Sent Events allow a web page (client) to get updates from a server. We’ll use this to automatically display new readings on the web server page when a new ESP-NOW packet arrives.
Important: Server-sent events are not supported on Internet Explorer.
OnDataRecv() function
The 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) {
Inside that 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 in the incomingData variable into the incomingReadings structure variable.
memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));
Then, create a JSON String variable with the received information (jsonString variable):
board["id"] = incomingReadings.id;
board["temperature"] = incomingReadings.temp;
board["humidity"] = incomingReadings.hum;
board["readingId"] = String(incomingReadings.readingId);
String jsonString = JSON.stringify(board);
Here’s an example on how the jsonString variable may look like after receiving the readings:
board = {
"id": "1",
"temperature": "24.32",
"humidity" = "65.85",
"readingId" = "2"
}
After gathering all the received data on the jsonString variable, send that information to the browser as an event (“new_readings”).
events.send(jsonString.c_str(), "new_readings", millis());
Later, we’ll see how to handle these events on the client side.
Finally, print the received information on the Arduino IDE Serial Monitor for debugging purposes:
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();
Building the Web Page
The index_html variable contains all the HTML, CSS and JavaScript to build the web page. We won’t go into details on how the HTML and CSS works. We’ll just take a look at how to handle the events sent by the server.
Handle Events
Create a new EventSource object and specify the URL of the page sending the updates. In our case, it’s /events.
if (!!window.EventSource) {
var source = new EventSource('/events');
Once you’ve instantiated an event source, you can start listening for messages from the server with addEventListener().
These are the default event listeners, as shown here 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 for “new_readings”.
source.addEventListener('new_readings', function(e) {
When the 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 that 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, print the new readings on the browser console, and put the received data into the elements with the corresponding id on the web page. We also update the date and time the readings were 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()
In the setup(), set 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 the 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 for the OnDataRecv callback function, so that it is executed when a new ESP-NOW packet arrives.
esp_now_register_recv_cb(OnDataRecv);
Handle Requests
When you access the ESP8266 IP address on the root / URL, send the text that is stored on the index_html variable 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()
In the loop(), send a ping every 5 seconds. This is used to check on the client side, if the server is still running (these lines are 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 following diagram summarizes how the Server-sent Events work on this project and how it updates the values without refreshing the web page.
After uploading the code to the receiver board, press the on-board EN/RST button. The ESP8266 IP address should be printed on the Serial Monitor as well as the Wi-Fi channel.
ESP8266 Sender Circuit
The ESP8266 sender boards are connected to a BME280 sensor. Wire the sensor to the default ESP8266 I2C pins:
- GPIO 5 (D1) -> SCL
- GPIO 4 (D2) -> SDA
ESP8266 Sender Code (ESP-NOW)
Each sender board will send a structure via ESP-NOW that contains the board ID (so that you can identify which board sent the readings), the temperature, the humidity and the reading ID. The reading ID is an int number to know how many messages were sent.
Upload the following code to each of your sender boards. Don’t forget to increment the id number for each sender board and insert your SSID in the WIFI_SSID variable.
/*
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
Start by importing the required libraries:
#include <espnow.h>
#include <ESP8266WiFi.h>
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
Set Board ID
Define the ESP8266 sender 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 receiver’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. The struct_message contains the board ID, temperature reading, humidity reading, and the reading ID.
typedef struct struct_message {
int id;
float temp;
float hum;
int readingId;
} struct_message;
Create a new variable of type struct_message that is called myData that stores the variables’ values.
struct_message myData;
Timer Interval
Create some auxiliary timer variables to publish the readings every 10 seconds. You can change the delay time on the interval variable.
unsigned long previousMillis = 0; // Stores last time temperature was published
const long interval = 10000; // Interval at which to publish sensor readings
Initialize the readingId variable – it keeps track of the number of readings sent.
unsigned int readingId = 0;
Changing Wi-Fi channel
Now, we’ll get the receiver’s Wi-Fi channel. This is useful because it allows us to automatically assign the same Wi-Fi channel to the sender board.
To do that, you must insert your SSID in the following line:
constexpr char WIFI_SSID[] = "REPLACE_WITH_YOUR_SSID";
Then, the getWiFiChannel() function scans for 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;
}
This snippet of code was proposed by Stephane (one of our readers). You can see his complete example here.
Initialize BME280 Sensor
The 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 from 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;
}
Note: to learn more about getting temperature and humidity from the BME280 sensor, read: ESP8266 with BME280 using Arduino IDE (Pressure, Temperature, Humidity).
OnDataSent Callback Function
The OnDataSent() callback function will be executed when a message is sent. In this case, this function prints if the message was successfully delivered or not.
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");
}
}
setup()
Initialize the Serial Monitor.
Serial.begin(115200);
Initialize the BME280 sensor:
initBME();
Set the 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 the ESP8266 role:
esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
After successfully initializing ESP-NOW, register the callback function that will be called when a message is sent. In this case, register for the OnDataSent() function created previously.
esp_now_register_send_cb(OnDataSent);
Add peer
To send data to another board (the receiver), you need to pair it as a peer. The following lines register and add the receiver as a peer.
esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);
loop()
In the loop(), check if it is time to get and send new readings.
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// Save the last time a new reading was published
previousMillis = currentMillis;
Send ESP-NOW Message
Finally, send the message structure via ESP-NOW.
esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
Recommended reading: Getting Started with ESP-NOW (ESP8266 with Arduino IDE)
Upload the code to your sender boards. You should notice that the boards change its Wi-Fi channel to the channel of the receiver board.
Demonstration
After uploading the code to all the boards and if everything is going as expected, the ESP8266 receiver board should start receiving sensor readings from the other boards.
Open a browser on your local network and type the ESP8266 IP address.
It should load the temperature, humidity and the last time the readings were updated on the web page for each board. Upon receiving a new packet, your web page updates automatically without refreshing the web page.
Wrapping Up
In this tutorial you’ve learned how to use ESP-NOW and Wi-Fi to setup a web server to receive ESP-NOW packets from multiple boards (many-to-one configuration) using the ESP8266 NodeMCU board. We have a similar project using the ESP32:
Additionally, you also used Server-Sent Events to automatically update the web page every time a new packet is received without refreshing the web page. We have a dedicated guide to Server-Sent Events:
If you like ESP8266, you might consider enrolling in our eBook “Home Automation using ESP8266“. You can also access our free ESP8266 resources here.
Thanks for reading.
Hi
What tool do you guys use to create the dashboard.
It is really difficult to manage / edit them with just a text editor.
Also to see the display without doing a whole code build and program
Ps nice project
Hi.
The dashboard is built using HTML + CSS.
You can use any text editor to write your HTML and CSS to build your web page.
We use VS Code.
Regards,
Sara
Hi what a nice project I have the problem Slave is Channel 11 and
the ESP8266 Master Channel 1 when I change the master to
wifi_set_channel(11); then it works. What should I change
I changed it to WiFi.mode(WIFI_MODE_AP);
Hi,
very interesting project. This is something I have looked for a long time. If my family gives me the time; – this project is my top prio.
Thanks for your ideas.
By the way: For what do you need 2x 4.7k Ohm resistor; listed?
Konrad
Hi.
Thanks.
You don’t need the resistors.
Copy/paste error. I’m sorry about that.
It is fixed now.
Regards,
Sara
Is there a limit on the number of senders. Can I have 10 to 20 senders and 1 receiver.
Hi.
Accordingly to the documentation:
Limited encrypted peers. 10 encrypted peers at the most are supported in Station mode; 6 at the most in SoftAP or SoftAP + Station mode;
Multiple unencrypted peers are supported, however, their total number should be less than 20, including encrypted peers;
Regards,
Sara
Hi again,
just a stupid question: Is it possible to realise this project also with different ESPs, like one ESP32 and two ESP8266; – and visa verso?
I just saw, that I have two ESP8266 left (of which one I wanted to take as receiver) and there was just another ESP32 left.
Hope this is not too stupid to ask.
Thanks
Konrad
Hi,
For your info: I have tried it (together with both tutorials (ESP32 and ESP8266) and it worked perfectly.
Therefore ignore the question above.
Again: This tutorial has solved some of my problems with MQTT / Raspi / Nodered connection. Big, big thanks to you.
Konrad
Shit…. Murphy’s law. It stopped working correctly.
Now I get the following message:
Station IP Address: 192.168.178.34
Wi-Fi Channel: 6
Client reconnected! Last message ID that it got is: 671831
And then nothing happens. I also think the Wi-Fi Channal was 1 when it worked well.
What did I wrong? Sorry; – I really feel now like a complete fool.
Konrad
I
It’s not a stupid question…I’m having a problem using 2 ESP8266 as Senders and 1 ESP32 as Receiver. Different mix works (ESP32 Sender and ESP826 Receiver).
I think that it’s a matter of channel assigment since the ESP is probably still working with the default channel (1) instead of 9 of the router. I raise the question to Rui… waiting.
Regards
Fiorenzo
Hi.
In that scenario, you need to get the ESP32 access point MAC address like this:
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_MODE_AP);
Serial.println(WiFi.softAPmacAddress());
}
void loop() {}
See this discussion here for more information:https://rntlab.com/question/esp8266-to-esp32-wifi-esp-now-problem/
Regards,
Sara
Hi Sara,
thank you for your help. Now it works with 2 ESP8266 Senders and 1 ESP32 Receiver!! Good job.
The secrets of the wifi, unbelivable, 2 MAC’s adresses!
Thanks also to Michel (the french guy)
Thanks again.
Fiorenzo
Hi.
If it wasn’t him, I still wouldn’t know how to make that work.
Regards,
Sara
Hi
It’s a team work
Michel
Hi,
Concerning my issue above: I think having found the issue and solved it. Or let me say; – it works since 5 days without complete stop.
Let me first explain the situation:
a.) I used 3 ESP8266 (I excluded the ESP32 to avoid further potential other issues; – although I think I know how to solve it, if the ESP32 is a sender).
b.) I started as discribed above with the senders -> no issues
c.) Then the receiver as discribed above. -> no issues
After a while; I found out in the browser client: No data sent! But Why?
It took me some time, but I could see, that the WiFi-Class seems to be different- But Why?
I could see, that this happened on 2 occaisons:
1.) Sometimes I had to adapt the receivers sketch. Suddenly there was this issue. Not always on all Senders and not always every time. Obviously the senders had different classes to the receiver.
2.) It happened often, when I switched off all browser clients (for example at night). After re-opening the browser the above mentionned issue happened once in a while, but regularly.
I decided to program a ESP Restart in the callback function. Very stupid like this, with a counter to avoid that it restarts to early:
// 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”);
if (zaehler < 5)
{
zaehler = zaehler + 1;
}
else
{
zaehler = 0;
//somit klappt die Verbindung nicht—> Restart des ESP8266
ESP.restart();
}
}
}
Since then no issues. This means, that if the sender does not find the receiver it restarts and checks again the WiFi class, etc.
I am sure that the same is applicable for the ESP32 (not tested yet).
Hope that helps others. If not just ignore it.
Neverthelss Sara and Rui –> you are so wonderfull with all your ideas for projects.
Thanks.
Konrad
Hello,
congrats for all of those tutorials, especially for this one. I was looking for that kind of thinks for such a long time! I’ve got a poor programmation level, as far as my english level so, I succed to use DHT 22 instead of BMP80, but I didn’t succed to have 3 and more Sending ESPs. My Receiver is a ESP 12E, and the senders are ESP01. No trouble with that so far.
Even if I succed to change the home page with 3 differents “Boards”, the Board#3 never upload with the temperature and humidity. But on the receiver’s serial, all of the 3 boards data are well loaded. I you can highlight my, I’ll appreciate! Anyway, congratulations again!
it’s OK now. I understood it was a problem of HTML. I made the comparisson line after line and found the problem. So happy! Thanks again!
Instead of the slave being a webserver I set the slave to communicate with Telegram
I have to slow the rate at which the sender sends data to the slave. If I do not slow the sender, new data will arrive before Telegram acts and I will not get any motion sensor notification that is connected to the sender. Even the data arrives corrrectly at the slave.
I also got the slave (the AP board that is connected to the router aand theerfore to Telegram) to send commands to the other board(to the sendor board)
So both boards send and recive but only one is access point.
The conclusion is that the board that has the telegram code must recive data at slow rate. Othherwise I will not get a messagee from telegram
If any one knows why please tell me
All the modified code is based on examples from this sight
Thanks Sara and Rui
PhilipTheArab
Could post your code? I couldn’t manage to receive data from another board AND after that connect to internet, wifi always timesout
Hello could you do this with multiple DS18B20 temperature sensors ?
Hi.
You can take a look at this tutorial and see if you can figure out the modifications: https://randomnerdtutorials.com/esp8266-ds18b20-temperature-sensor-web-server-with-arduino-ide/
Regards,
Sara
Is it possible to display the min and max values of the temp and humidity readings over a 24hr period? Perhaps where is says Last reading under the Temp and Humidity?.
Hi
This is a very interesting project. Thank you Sara and Rui.
Although my knowledge is very low, I made some changes and was able to simultaneously use 3 senders (ESP8266-01 with DS18B20) on the receiver (ESP8266-12F).
Now I am trying to add the possibility of connecting 3 relays on the receiver to control them using a threshold field (already added to each of the sender cards). That is, if the received temperature is below the threshold, the relay should be ON but if the temperature is above this value, the relay should go OFF. This is where I am now lost because I cannot figure out how to use in the relays the temperature values received.
For the output (to control the relays), I am using this project as a reference: https://randomnerdtutorials.com/esp32-esp8266-thermostat-web-server/
Is there anyone who can give me some ideas on how I can move forward?
Thank you.
Paulo
Hi.
I’m not sure if I understood your question.
But I think this tutorial might help:
https://randomnerdtutorials.com/esp32-relay-module-ac-web-server/
Regards,
Sara
Hello Sara,
Well, that tutorial I was able to do, too.
I think I do not explain well myself. What I am not able to understand is how I can use the values received from the sender boards to make the receiver board control the relays.
In your tutorial https://randomnerdtutorials.com/esp32-esp8266-thermostat-web-server/ I replace the LED with a RELAY, and it works well. Relay opens and closes according to the temperature read by the sensor.
In this https://randomnerdtutorials.com/esp8266-esp-now-wi-fi-web-server/, I built 3 “ESP-NOW Sender” cards, where I replace BME280 sensor with a DS18B20.
I also built an “ESP-NOW Receiver” and eliminated the moisture cards. On each of the three temperature cards I placed a field for Threshold, a “Submit” button, and an ON/OFF flag (as in thermostat-web-server). In the DASHBOARD the three cards work well and change the desired temperature (Threshold), also works well.
My problem now is how to use the temperature value that is represented on each card to activate the corresponding relay. When using:
float temperature01 = incomingReadings.temp; //From sender “board#1” to Relay01
And
float temperature02 = incomingReadings.temp; //From sender “board#2” to Relay02
the relays open and close depending on the last temperature received, regardless of which was the sender board, of course.
Now, what I am trying to do is create something like:
float temperature01 = incomingReadingsBoard#1.temp; //From sender “board#1” to Relay01
And
float temperature02 = incomingReadingsBoard#2.temp; //From sender “board#2” to Relay02
And
float temperature03 = incomingReadingsBoard#3.temp; //From sender “board#3″ to Relay03
Then I will use something similar to this (from the other project):
float temperature02 = incomingReadingsBoard#2.temp; //sensors.getTempCByIndex(0);
Serial.print(temperature02);
Serial.println(” *C”);
lastTemperature02 = String(temperature02);
// Check if temperature is above threshold and if it needs to trigger Relay
if(temperature02 > inputMessageA02.toFloat() && inputMessageB02 == "true" && !triggerActive){
String message = String("Temperature above threshold. Current temperature: ") +
String(temperature01) + String("C");
Serial.println(message);
triggerActive = true;
digitalWrite(Relay02, HIGH);
}
// Check if temperature is below threshold and if it needs to trigger Relay
else if((temperature02 < inputMessageA02.toFloat()) && inputMessageB02 == "true" && triggerActive) {
String message = String("Temperature below threshold. Current temperature: ") +
String(temperature01) + String(" C");
Serial.println(message);
triggerActive = false;
digitalWrite(Relay02, LOW);
I will do some more research… 🙂
Thank you.
Paulo
Hi.
You need to keep in mind that if each relay is controlled by a specific temperature sensor, then, you need to have different variables for each relay.
Regards,
Sara
Can you post the code with ds18b20 sensors?
First, I love your tutorials!
Second, this one is spot on for something I am trying to do – this is a perfect foundational element
Third, it complied and worked great using the Arduino IDE.
So foremost, thank you very much!!!
However, I am migrating my projects to VS Code for multiple reasons and haven’t been able to get this to compile using the PlatformIO extension even though every other one of your tutorials I tried compiled and ran fine.
The (first) error I am getting is:
C:\users\bs-ma.platformio\packages\framework-arduinoespressif8266\tools\sdk\include/espnow.h:41:35: error: typedef ‘esp_now_recv_cb_t’ is initialized (use decltype instead)
(There are subsequent ones, but I think it is a cascading problem.)
Clearly this is my problem not yours, but I would appreciate any insights you may have about how to get my PlatformIO configuration straightened out or a tip for a resource to investigate?
Hi Robert.
I’ve searched for a while, but unfortunately, I couldn’t find any solution.
If you find something, please share it. It may be useful for other readers too.
I’m sorry that I can’t help much.
Regards,
Sara
Thank you for your efforts!
Originally I was going to use the techniques in your excellent Websockets tutorial for the information sharing (which compiles fine under PlatformIO); but NOW is actually a little more attractive.
The ESP-NOW tutorial also compiles fine, so there must be something conflicting with AsyncWebserver libraries and NOW in my installation.
If / when I get it sorted out, I’ll let you know.
Thanks again!
First, thanks for sharing your knowledge.
Could I fix an ip in my receiver?
Hi.
Yes.
To give it a fix IP address, you can follow this tutorial: https://randomnerdtutorials.com/esp8266-nodemcu-static-fixed-ip-address-arduino/
Regards,
Sara
i have tried but using the libraries: ESPAsyncWebServer, ESPAsyncTCP the IP continues dynamic, could you give me a tip about whats is happening, please
😀
Hello how are you? I hope my English can be understood. I’ve searched, but can’t find information about the usefulness of the third boolean argument in source.addEventListener (). Could someone clarify this question? Thank you very much in advance for posting such useful information.
Great tutorial! Exactly what I was looking for. I just put some lines before esp_now_send() to emulate two BME devices for testing the sender code:
long rand = random(0, 2000);
myData.id = rand % 2 + 1;
myData.temp = 10.0 + (float) rand / 100.0;
myData.hum = 40.0 + (float) rand / 50.0;;
myData.readingId = readingId++;
Not searhing for the WiFi channel reduces the connection time of the sender to below 100ms! Therfore the ESP Now method is ideal for battery powered ESP applications where the sender goes to deepSleep after sending the data. Before I was using a REST like HTTP POST request which took about 400 to 1200ms to complete when not issuing a WiFi.begin() but relying o the persistent WiFi autoconnect instead. Ignoring the sleep current, a device should last at least 4 times longer with one set of batteries using ESP Now!
Btw. nice looking and simple to use Web page implementation for the server part, I like it.
hello
thanks for your great projects
can use ESP-NOW Two-Way Communication Between two ESP8266 NodeMCU Boards
that one of them is also web server?
(same this project: https://randomnerdtutorials.com/esp-now-two-way-communication-esp8266-nodemcu/
but one of them is web server)
thank you very much for answer
i mix both tutorials and its work very well
thanks agian
Hello, thanks you for this amazing tutorial and sharing your acknowledge. I use a 8266 devkit as receiver ,esp12S as senders and arduino ide. Everything works fine but I don’t know why we need to get the receiver’s Wi-Fi channel if senders use espnow. Is it because wifi and espnow must use de same channel? Another thing, monitoring senders via serial monitor on arduino ide I get “Delivery success” even if I disconnect the receiver, so I add WiFi.disconnect(); after getWiFiChannel(WIFI_SSID); and now, if I disconnect the receiver I get “Delivery fail” as should be … ( I think so) . Sorry for my awfull english, and thanks you very much
First of all congratulations for the tutorial and congratulations to everyone for the contribution of information and knowledge, my English and from Google, so sorry, I have a question, wanting to use the now protocol to transmit between 4 slave boards and a master (only the master has access to wifi network, so the option to check the channel seems useless for the slave, correct?), in turn the master with network access will be able to transmit and receive data via http / as a server or TCP communication .. ..but won’t it create problems with NOW receptions? how can they be managed in order not to miss broadcasts? Thank you
Hi can help Me, I’m trying to integrate esp now with modbus TCP, but I can’t transfer the board value to the Modbus server … where am I wrong? this is code
/*
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp-now-many-to-one-esp8266-nodemcu/
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 <ESP8266WiFi.h>
#include <espnow.h>
#include <ModbusIP_ESP8266.h>
// Modbus Registers Offsets
int MB1=1;
int MB2=2;
int MB3=3;
int MB4=4;
//ModbusIP object
ModbusIP mb;
const char* ssid = “xxxx”;
const char* password = “xxx”;
const int ledPin8 = 15;
// Structure example to receive data
// Must match the sender structure
typedef struct struct_message {
int id;
int A;
int B;
int C;
int D;
} struct_message;
// Create a struct_message called myData
struct_message myData;
// Create a structure to hold the readings from each board
struct_message board1;
// Create an array with all the structures
struct_message boardsStruct[5] = {board1,};
// Callback function that will be executed when data is received
void OnDataRecv(uint8_t * mac_addr, uint8_t *incomingData, uint8_t len) {
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(&myData, incomingData, sizeof(myData));
Serial.printf(“Board ID %u: %u bytes\n”, myData.id, len);
// Update the structures with the new incoming data
boardsStruct[myData.id-1].A = myData.A;
boardsStruct[myData.id-1].B = myData.B;
boardsStruct[myData.id-1].C = myData.C;
boardsStruct[myData.id-1].D = myData.D;
Serial.printf(“A value: %d \n”, boardsStruct[myData.id-1].A);
Serial.printf(“B value: %d \n”, boardsStruct[myData.id-1].B);
Serial.printf(“C value: %d \n”, boardsStruct[myData.id-1].C);
Serial.printf(“D value: %d \n”, boardsStruct[myData.id-1].D);
Serial.println();
}
void setup() {
pinMode(ledPin8, OUTPUT);
// Initialize Serial Monitor
Serial.begin(115200);
Serial.print(“ESP Board MAC Address: “);
Serial.println(WiFi.macAddress());
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());
mb.server();
mb.addHreg(MB1, 0x0000);
mb.addHreg(MB2, 0x0000);
mb.addHreg(MB3, 0x0000);
mb.addHreg(MB4, 0x0000);
// 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_set_self_role(ESP_NOW_ROLE_SLAVE);
esp_now_register_recv_cb(OnDataRecv);
}
void loop() {
//Call once inside loop() – all magic here
mb.task();
delay(10);
mb.addHreg(MB1,boardsStruct[0].A);
mb.addHreg(MB2,boardsStruct[0].B);
mb.addHreg(MB3,boardsStruct[0].C);
mb.addHreg(MB4,boardsStruct[0].D);
delay (10);
}
I set a Nodemcu as receiver and a esp-01 as a sender. The range between them is very small, one meter.
Can I do something to increase the range?
Hi.
I’m not sure, but that’s probably because the ESP-01 has a bad communication range.
Probably if you try two ESP8266 NodeMCU boards, you’ll get a higher range.
Regards,
Sara
Can I programm the sender to transmit data to two or more receivers? I will recall function esp_now_add_peer to give new broadcast adress. Must do something else? I have a clock as receiver with few senders with diferent sensors. But I have other clocks in the house. I want to use one sender with neo6m satelit receiver to transmit exact time to every clocks in the house.
Impossible for me to send a http request after receiving and espnow event on the receiving end. Wifi connection always times out.
Possible to do this with the mq2 sensor ?
Hi:
Thanks for all the effort and time! Your tutorials are very useful.
Thanks a lot for these great examples!! With this I created 2 sensorservers with soilsensors in the garden. To save battery I let them deepsleep for 70 minutes after they sent their data to the client correctly. This works perfectly. The client receives all the messages and displays their values correctly on the webserver. The problem is that whenever I start a new webbrowser session I have to wait max. 70 minutes before the data is displayed, while the client already has the data I want to see. The same happens when I refresh the browser window (I use Chrome). I am looking for a way to push data to the webserver in between readings. Tried to events.send(jsonString.c_str()) after filling jsonString but that does not work. What can I do? Any suggestions plz.
Hi.
You can make a request to the server when you open a new window on the browser on a specific URL (use Javascript).
When the ESP receives that request, it should send the readings to the client. Then, you should handle the data on the client using javascript for example.
Check this example: https://randomnerdtutorials.com/esp32-web-server-gauges/
Note that it makes a request when the web browser loads:
// Get current sensor readings when the page loads
window.addEventListener(‘load’, getReadings);
Then, handle the response. In that example, it is like this:
function getReadings(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myObj = JSON.parse(this.responseText);
console.log(myObj);
var temp = myObj.temperature;
var hum = myObj.humidity;
gaugeTemp.value = temp;
gaugeHum.value = hum;
}
};
xhr.open(“GET”, “/readings”, true);
xhr.send();
}
Then, the ESP32 should handle that request on the /readings URL:
server.on(“/readings”, HTTP_GET, [](AsyncWebServerRequest *request){
String json = getSensorReadings();
request->send(200, “application/json”, json);
json = String();
});
I think if you take a look at that example you’ll get an idea of how you can implement it in your project.
I hope this helps,
Regards,
Sara
Super thanks for your reply Sara! Your answer might be too difficult for me to understand. I am a complete newbee so I will follow the example you named and try to understand how it works. Give me some time! I will let you know when I puzzled it out. Many many thanks for tutorials like this.
Never mind 🙂
I tried putting the void my_function() {code} before the void setup and it works.. But if I put in below void loop, it does not. Just so I’ll know can you tell me why? Just wondering.
Thank you.
Hi.
The code runs linearly line by line. So, if you call the function before it is declared, you’ll get an error because the compiler didn’t find the function yet.
You must declare a function before calling it.
That error didn’t happen in previous versions of the Arduino IDE (I’m not sure why, I guess it compiled differently).
Regards,
Sara
Hello,
I have an issue that I hope you can explain… First, everything is working great. My question is why I can’t seem to add any “sub functions” i.e. void my_function() and call that function in my code. Whenever I try to utilize this method, “my_function();” in code and compile for download to esp8266 arduino returns an error “my_function” was not declared in this scope. It seems to have to do with the “const char index_html[] PROGMEM = R”rawliteral(……” part of your original code. I say that because I slowly added your code to a new script until I had the problem.
Is this normal? And is there a workaround?
P.S. This is the first time I’ve found and use your site and I have to say I’m so glad I found it. Wonderfully explained and easy to follow.
Thank You.
i have 3 questions.
I have 2 Esp8266 sender send data to 1 Esp8266 receiver. Can i use Esp8266 receiver publish data to my web server, not Async Web Server ??
How far 2 esp8266 now communicate??
Can I send data A from Esp8266(1) to Esp8266 (2), then Esp8266 (2) send data A to Esp8266 (3)??
Thanks.
Hi.
Yes. All of that is possible.
Regards,
Sara
I want to ask about ESP-NOW, i want to use this protocol for my project.
My project is about WSN with 3 nodes and 1 receiver. I’m using ESP8266 for this project. The nodes has 3 sensors in it which is a flame sensor, DHT22, and MQ5. The Receiver job is to display the readings to a display and send the data readings to telegram.
My problem with it is when i turn all of my nodes on, the receiver only updates 1 node data, and the other 2 nodes data is not updating in real-time.
My question is how to make the receiver, updates all 3 nodes data in real time? Can this guide work for sending notifications to telegram?
Hi.
I didn’t understand what you mean by “receiving data in real time”.
The receiver cannot receive multiple packages at the same time. It receives one after the other.
Yes, I think you can use Telegram without any problem. We have several tutorials explaining how to use telegram: https://randomnerdtutorials.com/?s=telegram
Regards,
Sara
Hi,
System show interesting behaviour. When I put two devices (ESP8266-MCU) 5 cm distance, most of the messages captured by receiver. But if I increase distance 30 cm or more receiver is not able to capture incoming sent by sender.
Do you have any suggestion about this? What may cause this problem? This is because I expect more distance while using ESP-NOW.
Best regads,
Orkun Gedik
Hi.
Yes, that’s not the usual behavior of ESP-NOW.
What boards are you using?
Regards,
Sara
Hi Sara,
I fixed the problem. It is my fault. I used different Wi-Fi channels on receiver and sender. When I set same channel on both parties problem resolved.
Thank you 🙂
Orkun Gedik
Hi, is it possible to host the webserver on the sender?
Yes you can, if you need to.
In this snippet:
function getDateTime() {
var currentdate = new Date();
var datetime = currentdate.getDate() + “/”
+ (currentdate.getMonth()+1) + “/”
+ currentdate.getFullYear() + ” at ”
+ currentdate.getHours() + “:”
+ currentdate.getMinutes() + “:”
+ currentdate.getSeconds();
return datetime;
}
The time is returned as a single digit…I would prefer if the Hour,Minute or Seconds were less than 10, the result would be in 2 digits…as in 01, 02, 03 etc…
I have tried multiple searches for a fix and think it must be fairly simple…thus the reason I can’t find the fix.
Can you help or suggest?
Hi.
Try it like this instead:
var dateTime = currentdate.getFullYear() + “/” +
(“00” + (currentdate.getMonth() + 1)).slice(-2) + “/” +
(“00″ + currentdate.getDate()).slice(-2) + ” ” +
(“00” + currentdate.getHours()).slice(-2) + “:” +
(“00” + currentdate.getMinutes()).slice(-2) + “:” +
(“00” + currentdate.getSeconds()).slice(-2);
Regards,
Sara
Hi. It’s almost the king of project that I need. BUT, as always, one thing is missing for me is that on the computer side, home computer, cellphone etc, I need a way to talk to one of the slave ESP8266 so it can send is data to the server. 8 slaves will send there data every 1-2 seconds but there is one slave that need to be told to send. So on the screen when I press a button that slave will send the data. All the slave have a micro-controller to drive them because the need for lots of i/o and analogs. Do you have a way to do that. Many thanks in advance. Dan Sept-05-2022
Is there a way to use a Sparkfun TMP117 temp sensor with this?
Hi Sara, nice tutorial, very useful.
Only one question?
What about a similar configuration:
one receiver with web server inside
multiple senders with sensors
one (or more) receiver with actuator (aca relay)
It’s possible? How can the receiver (web server) absolve the three job?
Hi Sara
I can’t run this example as I can’t find the library ESPNOW. It does appear in the available library list on the Arduino IDE
Claude
Hi.
It’s included by default.
Make sure you have the right board selected before trying to compile the code.
Regards,
Sara
Hi
Right it works with a ESP8266 but not with a ESP32. My board is a ESP32 WROOM
What should be the code for a ESP32
Regards
Claude