{"id":96436,"date":"2020-08-21T13:08:00","date_gmt":"2020-08-21T13:08:00","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=96436"},"modified":"2025-03-14T16:42:46","modified_gmt":"2025-03-14T16:42:46","slug":"esp32-esp-now-wi-fi-web-server","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp32-esp-now-wi-fi-web-server\/","title":{"rendered":"ESP32: ESP-NOW Web Server Sensor Dashboard (ESP-NOW + Wi-Fi)"},"content":{"rendered":"\n<p>In this project, you&#8217;ll learn how to host an ESP32 web server and use ESP-NOW communication protocol simultaneously. You can have several ESP32 boards sending sensor readings via ESP-NOW to one ESP32 receiver that displays all readings on a web server. The boards will be programmed using Arduino IDE.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" width=\"1200\" height=\"675\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP32-ESP-NOW-Web-Server-Sensor-Dashboard-ESP-NOW-Wi-Fi.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32: ESP-NOW Web Server Sensor Dashboard using Arduino IDE (ESP-NOW and Wi-Fi simultaneously)\" class=\"wp-image-96913\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP32-ESP-NOW-Web-Server-Sensor-Dashboard-ESP-NOW-Wi-Fi.jpg?w=1280&amp;quality=100&amp;strip=all&amp;ssl=1 1280w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP32-ESP-NOW-Web-Server-Sensor-Dashboard-ESP-NOW-Wi-Fi.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP32-ESP-NOW-Web-Server-Sensor-Dashboard-ESP-NOW-Wi-Fi.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP32-ESP-NOW-Web-Server-Sensor-Dashboard-ESP-NOW-Wi-Fi.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p>We have other guides related to ESP-NOW that you might be interested in:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp-now-esp32-arduino-ide\/\">Getting Started with ESP-NOW (ESP32 with Arduino IDE)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp-now-two-way-communication-esp32\/\">ESP-NOW Two-Way Communication Between ESP32 Boards<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp-now-one-to-many-esp32-esp8266\/\">ESP-NOW with ESP32: Send Data to Multiple Boards (one-to-many)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp-now-many-to-one-esp32\/\">ESP-NOW with ESP32: Receive Data from Multiple Boards (many-to-one)<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Watch the Video Tutorial<\/h2>\n\n\n<p style=\"text-align:center\"><iframe width=\"720\" height=\"405\" src=\"https:\/\/www.youtube.com\/embed\/OLP-HwU36rU?rel=0\" frameborder=\"0\" allowfullscreen><\/iframe><\/p>\n\n\n\n<p class=\"rntbox rntcorange\"><strong>Note: <\/strong> we&#8217;ve updated this tutorial with a better method to use ESP-NOW and Wi-Fi simultaneously. The video doesn&#8217;t use this current method. You can still watch the video to see how everything works, but we recommend that you take a look at the written article.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Using ESP-NOW and Wi-Fi Simultaneously<\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"902\" height=\"865\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/08\/ESP-NOW-With-Wi-Fi-Web-Server-How-It-Works.png?resize=902%2C865&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Using ESP-NOW and Wi-Fi Simultaneously: ESP-NOW Receiver Web Server and ESP-NOW Sender boards\" class=\"wp-image-98801\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/08\/ESP-NOW-With-Wi-Fi-Web-Server-How-It-Works.png?w=902&amp;quality=100&amp;strip=all&amp;ssl=1 902w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/08\/ESP-NOW-With-Wi-Fi-Web-Server-How-It-Works.png?resize=300%2C288&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/08\/ESP-NOW-With-Wi-Fi-Web-Server-How-It-Works.png?resize=768%2C736&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 902px) 100vw, 902px\" \/><\/figure>\n\n\n\n<p>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:<\/p>\n\n\n\n<ul><li>The ESP32 sender boards must use the same Wi-Fi channel of the receiver board.<\/li><li>The Wi-Fi channel of the receiver board is automatically assigned by your Wi-Fi router.<\/li><li>The Wi-Fi mode of the receiver board must be access point and station (<span class=\"rnthl rntliteral\">WIFI_AP_STA<\/span>).<\/li><li>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.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Project Overview<\/h2>\n\n\n\n<p>The following diagram shows a high-level overview of the project we&#8217;ll build.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"908\" height=\"870\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP-NOW-Web-Server-REceiver-Two-Sender-Board-how-it-works.png?resize=908%2C870&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP-NOW Receiver Web Server and ESP32 boards sending temperature humidity readings with ESP-NOW\" class=\"wp-image-96723\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP-NOW-Web-Server-REceiver-Two-Sender-Board-how-it-works.png?w=908&amp;quality=100&amp;strip=all&amp;ssl=1 908w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP-NOW-Web-Server-REceiver-Two-Sender-Board-how-it-works.png?resize=300%2C287&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP-NOW-Web-Server-REceiver-Two-Sender-Board-how-it-works.png?resize=768%2C736&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 908px) 100vw, 908px\" \/><\/figure><\/div>\n\n\n<ul class=\"wp-block-list\">\n<li>There are two ESP32 sender boards that send <a href=\"https:\/\/makeradvisor.com\/tools\/dht22-temperature-humidity-sensor\/\" target=\"_blank\" rel=\"noreferrer noopener\">DHT22<\/a> temperature and humidity readings via ESP-NOW to one ESP32 receiver board (<a href=\"https:\/\/randomnerdtutorials.com\/esp-now-many-to-one-esp32\/\">ESP-NOW many to one configuration<\/a>);<\/li>\n\n\n\n<li>The ESP32 receiver board receives the packets and displays the readings on a web server;<\/li>\n\n\n\n<li>The web server is updated automatically every time it receives a new reading using Server-Sent Events (SSE).<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<p>Before proceeding with this project, make sure you check the following prerequisites.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Arduino IDE<\/h3>\n\n\n\n<p>We\u2019ll program the ESP32 boards using Arduino IDE, so before proceeding with this tutorial, make sure you have the ESP32 board installed in your Arduino IDE.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/installing-esp32-arduino-ide-2-0\/\" title=\"\">Installing ESP32 Board in Arduino IDE (Windows, Mac OS X, and Linux)<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Installing Libraries<\/h3>\n\n\n\n<p>For this project, you need to install the following libraries:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/adafruit\/DHT-sensor-library\" target=\"_blank\" rel=\"noreferrer noopener\">DHT library from Adafruit<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/adafruit\/Adafruit_Sensor\" target=\"_blank\" rel=\"noreferrer noopener\">Adafruit Unified Sensor library<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/arduino-libraries\/Arduino_JSON\" target=\"_blank\" rel=\"noopener\" title=\"\">Arduino_JSON library<\/a> by Arduino<\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/ESP32Async\/ESPAsyncWebServer\" target=\"_blank\" rel=\"noopener\" title=\"\">ESPAsyncWebServer&nbsp;<\/a>by ESP32Async<\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/ESP32Async\/AsyncTCP\" target=\"_blank\" rel=\"noopener\" title=\"\">AsyncTCP<\/a> by ESP32Async<\/li>\n<\/ul>\n\n\n\n<p>You can install the Libraries via the Arduino Library Manager. Go to&nbsp;<strong>Sketch&nbsp;<\/strong>&gt;&nbsp;<strong>Include Library<\/strong>&nbsp;&gt;&nbsp;<strong>Manage Libraries<\/strong>&nbsp;and search for the libraries&#8217; names to install them.<\/p>\n\n\n\n<p class=\"rntbox rntclblue\">To learn more about the DHT11 or DHT22 temperature sensor, read our guide:&nbsp;<a href=\"https:\/\/randomnerdtutorials.com\/esp32-dht11-dht22-temperature-humidity-sensor-arduino-ide\/\">ESP32 with DHT11\/DHT22 Temperature and Humidity Sensor using Arduino IDE<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Parts Required<\/h2>\n\n\n\n<p>To follow this tutorial, you need multiple ESP32 boards. We&#8217;ll use three ESP32 boards. You also need:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>3x <a href=\"https:\/\/makeradvisor.com\/tools\/esp32-dev-board-wi-fi-bluetooth\/\" target=\"_blank\" rel=\"noreferrer noopener\">ESP32<\/a>&nbsp;(read&nbsp;<a href=\"https:\/\/makeradvisor.com\/esp32-development-boards-review-comparison\/\" target=\"_blank\" rel=\"noreferrer noopener\">Best ESP32 development boards<\/a>)<\/li>\n\n\n\n<li>2x <a href=\"https:\/\/makeradvisor.com\/tools\/dht22-temperature-humidity-sensor\/\" target=\"_blank\" rel=\"noreferrer noopener\">DHT22 temperature and humidity sensor<\/a> &#8211; <a href=\"https:\/\/randomnerdtutorials.com\/esp32-dht11-dht22-temperature-humidity-sensor-arduino-ide\/\">DHT guide for ESP32<\/a><\/li>\n\n\n\n<li>2x <a href=\"https:\/\/makeradvisor.com\/tools\/resistors-kits\/\" target=\"_blank\" rel=\"noreferrer noopener\">4.7k Ohm resistor<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/mb-102-solderless-breadboard-830-points\/\" target=\"_blank\" rel=\"noreferrer noopener\">Breadboard<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/jumper-wires-kit-120-pieces\/\" target=\"_blank\" rel=\"noreferrer noopener\">Jumper wires<\/a><\/li>\n<\/ul>\n\n\n<p>You can use the preceding links or go directly to <a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\">MakerAdvisor.com\/tools<\/a> to find all the parts for your projects at the best price!<\/p><p style=\"text-align:center;\"><a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2017\/10\/header-200.png?w=1200&#038;quality=100&#038;strip=all&#038;ssl=1\"><\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Getting the Receiver Board MAC Address<\/h2>\n\n\n\n<p>To send messages via ESP-NOW, you need to know the receiver board\u2019s <a href=\"https:\/\/randomnerdtutorials.com\/get-change-esp32-esp8266-mac-address-arduino\/\">MAC address<\/a>. Each board has a unique MAC address (learn how to <a href=\"https:\/\/randomnerdtutorials.com\/get-change-esp32-esp8266-mac-address-arduino\/\">Get and Change the ESP32 MAC Address<\/a>).<\/p>\n\n\n\n<p>Upload the following code to your ESP32 receiver board to get its MAC address.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*\n  Rui Santos &amp; Sara Santos - Random Nerd Tutorials\n  Complete project details at https:\/\/RandomNerdTutorials.com\/get-change-esp32-esp8266-mac-address-arduino\/\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.  \n  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\/\n#ifdef ESP32\n  #include &lt;WiFi.h&gt;\n  #include &lt;esp_wifi.h&gt;\n#else\n  #include &lt;ESP8266WiFi.h&gt;\n#endif\n\nvoid setup(){\n  Serial.begin(115200);\n\n  Serial.print(&quot;ESP Board MAC Address: &quot;);\n  #ifdef ESP32\n    WiFi.mode(WIFI_STA);\n    WiFi.STA.begin();\n    uint8_t baseMac[6];\n    esp_err_t ret = esp_wifi_get_mac(WIFI_IF_STA, baseMac);\n    if (ret == ESP_OK) {\n      Serial.printf(&quot;%02x:%02x:%02x:%02x:%02x:%02x\\n&quot;,\n                    baseMac[0], baseMac[1], baseMac[2],\n                    baseMac[3], baseMac[4], baseMac[5]);\n    } else {\n      Serial.println(&quot;Failed to read MAC address&quot;);\n    }\n  #else\n    Serial.println(WiFi.macAddress());\n  #endif\n}\n \nvoid loop(){\n\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP\/ESP_Get_MAC_Address.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>After uploading the code, press the RST\/EN button, and the MAC address should be displayed on the Serial Monitor. <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"601\" height=\"445\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-MAC-Address-Serial-Monitor.png?resize=601%2C445&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 board MAC Address with Arduino IDE Serial Monitor\" class=\"wp-image-96297\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-MAC-Address-Serial-Monitor.png?w=601&amp;quality=100&amp;strip=all&amp;ssl=1 601w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/04\/ESP32-MAC-Address-Serial-Monitor.png?resize=300%2C222&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 601px) 100vw, 601px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">ESP32 Receiver (ESP-NOW + Web Server)<\/h2>\n\n\n\n<p>The ESP32 receiver board receives the packets from the sender boards and hosts a web server to display the latest received readings.<\/p>\n\n\n\n<p>Upload the following code to your receiver board &#8211; the code is prepared to receive readings from two different boards.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*\n  Rui Santos &amp; Sara Santos - Random Nerd Tutorials\n  Complete project details at https:\/\/RandomNerdTutorials.com\/esp32-esp-now-wi-fi-web-server\/\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.  \n  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\/\n#include &lt;esp_now.h&gt;\n#include &lt;WiFi.h&gt;\n#include &quot;ESPAsyncWebServer.h&quot;\n#include &lt;Arduino_JSON.h&gt;\n\n\/\/ Replace with your network credentials (STATION)\nconst char* ssid = &quot;REPLACE_WITH_YOUR_SSID&quot;;\nconst char* password = &quot;REPLACE_WITH_YOUR_PASSWORD&quot;;\n\n\/\/ Structure example to receive data\n\/\/ Must match the sender structure\ntypedef struct struct_message {\n  int id;\n  float temp;\n  float hum;\n  unsigned int readingId;\n} struct_message;\n\nstruct_message incomingReadings;\n\nJSONVar board;\n\nAsyncWebServer server(80);\nAsyncEventSource events(&quot;\/events&quot;);\n\n\/\/ callback function that will be executed when data is received\nvoid OnDataRecv(const uint8_t * mac_addr, const uint8_t *incomingData, int len) { \n  \/\/ Copies the sender mac address to a string\n  char macStr[18];\n  Serial.print(&quot;Packet received from: &quot;);\n  snprintf(macStr, sizeof(macStr), &quot;%02x:%02x:%02x:%02x:%02x:%02x&quot;,\n           mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);\n  Serial.println(macStr);\n  memcpy(&amp;incomingReadings, incomingData, sizeof(incomingReadings));\n  \n  board[&quot;id&quot;] = incomingReadings.id;\n  board[&quot;temperature&quot;] = incomingReadings.temp;\n  board[&quot;humidity&quot;] = incomingReadings.hum;\n  board[&quot;readingId&quot;] = String(incomingReadings.readingId);\n  String jsonString = JSON.stringify(board);\n  events.send(jsonString.c_str(), &quot;new_readings&quot;, millis());\n  \n  Serial.printf(&quot;Board ID %u: %u bytes\\n&quot;, incomingReadings.id, len);\n  Serial.printf(&quot;t value: %4.2f \\n&quot;, incomingReadings.temp);\n  Serial.printf(&quot;h value: %4.2f \\n&quot;, incomingReadings.hum);\n  Serial.printf(&quot;readingID value: %d \\n&quot;, incomingReadings.readingId);\n  Serial.println();\n}\n\nconst char index_html[] PROGMEM = R&quot;rawliteral(\n&lt;!DOCTYPE HTML&gt;&lt;html&gt;\n&lt;head&gt;\n  &lt;title&gt;ESP-NOW DASHBOARD&lt;\/title&gt;\n  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;\n  &lt;link rel=&quot;stylesheet&quot; href=&quot;https:\/\/use.fontawesome.com\/releases\/v5.7.2\/css\/all.css&quot; integrity=&quot;sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr&quot; crossorigin=&quot;anonymous&quot;&gt;\n  &lt;link rel=&quot;icon&quot; href=&quot;data:,&quot;&gt;\n  &lt;style&gt;\n    html {font-family: Arial; display: inline-block; text-align: center;}\n    p {  font-size: 1.2rem;}\n    body {  margin: 0;}\n    .topnav { overflow: hidden; background-color: #2f4468; color: white; font-size: 1.7rem; }\n    .content { padding: 20px; }\n    .card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }\n    .cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }\n    .reading { font-size: 2.8rem; }\n    .packet { color: #bebebe; }\n    .card.temperature { color: #fd7e14; }\n    .card.humidity { color: #1b78e2; }\n  &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;div class=&quot;topnav&quot;&gt;\n    &lt;h3&gt;ESP-NOW DASHBOARD&lt;\/h3&gt;\n  &lt;\/div&gt;\n  &lt;div class=&quot;content&quot;&gt;\n    &lt;div class=&quot;cards&quot;&gt;\n      &lt;div class=&quot;card temperature&quot;&gt;\n        &lt;h4&gt;&lt;i class=&quot;fas fa-thermometer-half&quot;&gt;&lt;\/i&gt; BOARD #1 - TEMPERATURE&lt;\/h4&gt;&lt;p&gt;&lt;span class=&quot;reading&quot;&gt;&lt;span id=&quot;t1&quot;&gt;&lt;\/span&gt; &amp;deg;C&lt;\/span&gt;&lt;\/p&gt;&lt;p class=&quot;packet&quot;&gt;Reading ID: &lt;span id=&quot;rt1&quot;&gt;&lt;\/span&gt;&lt;\/p&gt;\n      &lt;\/div&gt;\n      &lt;div class=&quot;card humidity&quot;&gt;\n        &lt;h4&gt;&lt;i class=&quot;fas fa-tint&quot;&gt;&lt;\/i&gt; BOARD #1 - HUMIDITY&lt;\/h4&gt;&lt;p&gt;&lt;span class=&quot;reading&quot;&gt;&lt;span id=&quot;h1&quot;&gt;&lt;\/span&gt; &amp;percnt;&lt;\/span&gt;&lt;\/p&gt;&lt;p class=&quot;packet&quot;&gt;Reading ID: &lt;span id=&quot;rh1&quot;&gt;&lt;\/span&gt;&lt;\/p&gt;\n      &lt;\/div&gt;\n      &lt;div class=&quot;card temperature&quot;&gt;\n        &lt;h4&gt;&lt;i class=&quot;fas fa-thermometer-half&quot;&gt;&lt;\/i&gt; BOARD #2 - TEMPERATURE&lt;\/h4&gt;&lt;p&gt;&lt;span class=&quot;reading&quot;&gt;&lt;span id=&quot;t2&quot;&gt;&lt;\/span&gt; &amp;deg;C&lt;\/span&gt;&lt;\/p&gt;&lt;p class=&quot;packet&quot;&gt;Reading ID: &lt;span id=&quot;rt2&quot;&gt;&lt;\/span&gt;&lt;\/p&gt;\n      &lt;\/div&gt;\n      &lt;div class=&quot;card humidity&quot;&gt;\n        &lt;h4&gt;&lt;i class=&quot;fas fa-tint&quot;&gt;&lt;\/i&gt; BOARD #2 - HUMIDITY&lt;\/h4&gt;&lt;p&gt;&lt;span class=&quot;reading&quot;&gt;&lt;span id=&quot;h2&quot;&gt;&lt;\/span&gt; &amp;percnt;&lt;\/span&gt;&lt;\/p&gt;&lt;p class=&quot;packet&quot;&gt;Reading ID: &lt;span id=&quot;rh2&quot;&gt;&lt;\/span&gt;&lt;\/p&gt;\n      &lt;\/div&gt;\n    &lt;\/div&gt;\n  &lt;\/div&gt;\n&lt;script&gt;\nif (!!window.EventSource) {\n var source = new EventSource('\/events');\n \n source.addEventListener('open', function(e) {\n  console.log(&quot;Events Connected&quot;);\n }, false);\n source.addEventListener('error', function(e) {\n  if (e.target.readyState != EventSource.OPEN) {\n    console.log(&quot;Events Disconnected&quot;);\n  }\n }, false);\n \n source.addEventListener('message', function(e) {\n  console.log(&quot;message&quot;, e.data);\n }, false);\n \n source.addEventListener('new_readings', function(e) {\n  console.log(&quot;new_readings&quot;, e.data);\n  var obj = JSON.parse(e.data);\n  document.getElementById(&quot;t&quot;+obj.id).innerHTML = obj.temperature.toFixed(2);\n  document.getElementById(&quot;h&quot;+obj.id).innerHTML = obj.humidity.toFixed(2);\n  document.getElementById(&quot;rt&quot;+obj.id).innerHTML = obj.readingId;\n  document.getElementById(&quot;rh&quot;+obj.id).innerHTML = obj.readingId;\n }, false);\n}\n&lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;)rawliteral&quot;;\n\nvoid setup() {\n  \/\/ Initialize Serial Monitor\n  Serial.begin(115200);\n\n  \/\/ Set the device as a Station and Soft Access Point simultaneously\n  WiFi.mode(WIFI_AP_STA);\n  \n  \/\/ Set device as a Wi-Fi Station\n  WiFi.begin(ssid, password);\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(1000);\n    Serial.println(&quot;Setting as a Wi-Fi Station..&quot;);\n  }\n  Serial.print(&quot;Station IP Address: &quot;);\n  Serial.println(WiFi.localIP());\n  Serial.print(&quot;Wi-Fi Channel: &quot;);\n  Serial.println(WiFi.channel());\n\n  \/\/ Init ESP-NOW\n  if (esp_now_init() != ESP_OK) {\n    Serial.println(&quot;Error initializing ESP-NOW&quot;);\n    return;\n  }\n  \n  \/\/ Once ESPNow is successfully Init, we will register for recv CB to\n  \/\/ get recv packer info\n  esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));\n\n  server.on(&quot;\/&quot;, HTTP_GET, [](AsyncWebServerRequest *request){\n    request-&gt;send(200, &quot;text\/html&quot;, index_html);\n  });\n   \n  events.onConnect([](AsyncEventSourceClient *client){\n    if(client-&gt;lastId()){\n      Serial.printf(&quot;Client reconnected! Last message ID that it got is: %u\\n&quot;, client-&gt;lastId());\n    }\n    \/\/ send event with message &quot;hello!&quot;, id current millis\n    \/\/ and set reconnect delay to 1 second\n    client-&gt;send(&quot;hello!&quot;, NULL, millis(), 10000);\n  });\n  server.addHandler(&amp;events);\n  server.begin();\n}\n \nvoid loop() {\n  static unsigned long lastEventTime = millis();\n  static const unsigned long EVENT_INTERVAL_MS = 5000;\n  if ((millis() - lastEventTime) &gt; EVENT_INTERVAL_MS) {\n    events.send(&quot;ping&quot;,NULL,millis());\n    lastEventTime = millis();\n  }\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/ESP_NOW_WiFi\/ESP_NOW_Receiver_Web_Server.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How the Code Works<\/h3>\n\n\n\n<p>First, include the necessary libraries.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include &lt;esp_now.h&gt;\n#include &lt;WiFi.h&gt;\n#include \"ESPAsyncWebServer.h\"\n#include &lt;Arduino_JSON.h&gt;<\/code><\/pre>\n\n\n\n<p>The <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/arduino-libraries\/Arduino_JSON\" target=\"_blank\"><span class=\"rnthl rntliteral\">Arduino_JSON<\/span> library<\/a> is needed because we&#8217;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&#8217;ll see later in this project. <\/p>\n\n\n\n<p>Insert your network credentials on the following lines so that the ESP32 can connect to your local network.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>const char* ssid = \"REPLACE_WITH_YOUR_SSID\";\nconst char* password = \"REPLACE_WITH_YOUR_PASSWORD\";<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Data Structure<\/h4>\n\n\n\n<p>Then, create a structure that contains the data we&#8217;ll receive. We called this structure <span class=\"rnthl rntliteral\">struct_message<\/span> and it contains the board ID, temperature and humidity readings, and the reading ID.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>typedef struct struct_message {\n    int id;\n    float temp;\n    float hum;\n    int readingId;\n} struct_message;<\/code><\/pre>\n\n\n\n<p>Create a new variable of type <span class=\"rnthl rntliteral\">struct_message<\/span> that is called <span class=\"rnthl rntliteral\">incomingReadings<\/span> that will store the variables&#8217; values.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>struct_message incomingReadings;<\/code><\/pre>\n\n\n\n<p>Create a JSON variable called <span class=\"rnthl rntliteral\">board<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>JSONVar board;<\/code><\/pre>\n\n\n\n<p>Create an Async Web Server on port 80.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>AsyncWebServer server(80);<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Create Event Source<\/h3>\n\n\n\n<p>To automatically display the information on the web server when a new reading arrives, we&#8217;ll use Server-Sent Events (SSE).<\/p>\n\n\n\n<p>The following line creates a new event source on <span class=\"rnthl rntliteral\">\/events<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>AsyncEventSource events(\"\/events\");<\/code><\/pre>\n\n\n\n<p>Server-Sent Events allow a web page (client) to get updates from a server. We&#8217;ll use this to automatically display new readings on the web server page when a new ESP-NOW packet arrives.<\/p>\n\n\n\n<p class=\"rntbox rntcred\"><strong>Important: <\/strong> Server-sent events are not supported on Internet Explorer.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">OnDataRecv() function<\/h3>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">OnDataRecv()<\/span> function will be executed when you receive a new ESP-NOW packet.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void OnDataRecv(const uint8_t * mac_addr, const uint8_t *incomingData, int len) {<\/code><\/pre>\n\n\n\n<p>Inside that function, print the sender&#8217;s MAC address:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Copies the sender mac address to a string\nchar macStr&#091;18];\nSerial.print(\"Packet received from: \");\nsnprintf(macStr, sizeof(macStr), \"%02x:%02x:%02x:%02x:%02x:%02x\",\n         mac_addr&#091;0], mac_addr&#091;1], mac_addr&#091;2], mac_addr&#091;3], mac_addr&#091;4], mac_addr&#091;5]);\nSerial.println(macStr);<\/code><\/pre>\n\n\n\n<p>Copy the information in the <span class=\"rnthl rntliteral\">incomingData<\/span> variable into the <span class=\"rnthl rntliteral\">incomingReadings<\/span> structure variable.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>memcpy(&amp;incomingReadings, incomingData, sizeof(incomingReadings));<\/code><\/pre>\n\n\n\n<p>Then, create a JSON String variable with the received information (<span class=\"rnthl rntliteral\">jsonString<\/span> variable):<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>board&#091;\"id\"] = incomingReadings.id;\nboard&#091;\"temperature\"] = incomingReadings.temp;\nboard&#091;\"humidity\"] = incomingReadings.hum;\nboard&#091;\"readingId\"] = String(incomingReadings.readingId);\nString jsonString = JSON.stringify(board);<\/code><\/pre>\n\n\n\n<p>Here&#8217;s an example of how the <span class=\"rnthl rntliteral\">jsonString<\/span> variable may look like after receiving the readings:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>board = {\n  \"id\": \"1\",\n  \"temperature\": \"24.32\",\n  \"humidity\" = \"65.85\",\n  \"readingId\" = \"2\"\n}<\/code><\/pre>\n\n\n\n<p>After gathering all the received data on the <span class=\"rnthl rntliteral\">jsonString<\/span> variable, send that information to the browser as an event (<span class=\"rnthl rntliteral\">&#8220;new_readings&#8221;<\/span>).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>events.send(jsonString.c_str(), \"new_readings\", millis());<\/code><\/pre>\n\n\n\n<p>Later, we&#8217;ll see how to handle these events on the client side. <\/p>\n\n\n\n<p>Finally, print the received information on the Arduino IDE Serial Monitor for debugging purposes:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.printf(\"Board ID %u: %u bytes\\n\", incomingReadings.id, len);\nSerial.printf(\"t value: %4.2f \\n\", incomingReadings.temp);\nSerial.printf(\"h value: %4.2f \\n\", incomingReadings.hum);\nSerial.printf(\"readingID value: %d \\n\", incomingReadings.readingId);\nSerial.println();<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Building the Web Page<\/h3>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">index_html<\/span> variable contains all the HTML, CSS and JavaScript to build the web page. We won&#8217;t go into details on how the HTML and CSS works. We&#8217;ll just take a look at how to handle the events sent by the server.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Handle Events<\/h4>\n\n\n\n<p>Create a new <span class=\"rnthl rntliteral\">EventSource<\/span> object and specify the URL of the page sending the updates. In our case, it&#8217;s <span class=\"rnthl rntliteral\">\/events<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>if (!!window.EventSource) {\n var source = new EventSource('\/events');<\/code><\/pre>\n\n\n\n<p>Once you&#8217;ve instantiated an event source, you can start listening for messages from the server with <span class=\"rnthl rntliteral\">addEventListener()<\/span>.<\/p>\n\n\n\n<p>These are the default event listeners, as shown here in the AsyncWebServer <a href=\"https:\/\/github.com\/me-no-dev\/ESPAsyncWebServer#setup-event-source-in-the-browser\" target=\"_blank\" rel=\"noreferrer noopener\">documentation<\/a>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>source.addEventListener('open', function(e) {\n  console.log(\"Events Connected\");\n}, false);\nsource.addEventListener('error', function(e) {\n if (e.target.readyState != EventSource.OPEN) {\n   console.log(\"Events Disconnected\");\n }\n}, false);\n\nsource.addEventListener('message', function(e) {\n console.log(\"message\", e.data);\n}, false);<\/code><\/pre>\n\n\n\n<p>Then, add the event listener for <span class=\"rnthl rntliteral\">&#8220;new_readings&#8221;<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>source.addEventListener('new_readings', function(e) {<\/code><\/pre>\n\n\n\n<p>When the ESP32 receives a new packet, it sends a JSON string with the readings as an event (<span class=\"rnthl rntliteral\">&#8220;new_readings&#8221;<\/span>) to the client. The following lines handle what happens when the browser receives that event.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>console.log(\"new_readings\", e.data);\nvar obj = JSON.parse(e.data);\ndocument.getElementById(\"t\"+obj.id).innerHTML = obj.temperature.toFixed(2);\ndocument.getElementById(\"h\"+obj.id).innerHTML = obj.humidity.toFixed(2);\ndocument.getElementById(\"rt\"+obj.id).innerHTML = obj.readingId;\ndocument.getElementById(\"rh\"+obj.id).innerHTML = obj.readingId;<\/code><\/pre>\n\n\n\n<p>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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">setup()<\/h3>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">setup()<\/span>, set the ESP32 receiver as an access point and Wi-Fi station:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>WiFi.mode(WIFI_AP_STA);<\/code><\/pre>\n\n\n\n<p>The following lines connect the ESP32 to your local network and print the IP address and the Wi-Fi channel:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Set device as a Wi-Fi Station\nWiFi.begin(ssid, password);\nwhile (WiFi.status() != WL_CONNECTED) {\n  delay(1000);\n  Serial.println(\"Setting as a Wi-Fi Station..\");\n}\nSerial.print(\"Station IP Address: \");\nSerial.println(WiFi.localIP());\nSerial.print(\"Wi-Fi Channel: \");\nSerial.println(WiFi.channel());<\/code><\/pre>\n\n\n\n<p>Initialize ESP-NOW.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (esp_now_init() != ESP_OK) {\n  Serial.println(\"Error initializing ESP-NOW\");\n  return;\n}<\/code><\/pre>\n\n\n\n<p>Register for the <span class=\"rnthl rntliteral\">OnDataRecv<\/span> callback function, so that it is executed when a new ESP-NOW packet arrives.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Handle Requests<\/h3>\n\n\n\n<p>When you access the ESP32 IP address on the root <span class=\"rnthl rntliteral\">\/<\/span> URL, send the text that is stored on the <span class=\"rnthl rntliteral\">index_html<\/span> variable to build the web page.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.on(\"\/\", HTTP_GET, &#091;](AsyncWebServerRequest *request){\n  request-&gt;send_P(200, \"text\/html\", index_html);\n});<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Server Event Source<\/h3>\n\n\n\n<p>Set up the event source on the server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>events.onConnect(&#091;](AsyncEventSourceClient *client){\n  if(client-&gt;lastId()){\n    Serial.printf(\"Client reconnected! Last message ID that it got is: %u\\n\", client-&gt;lastId());\n  }\n  \/\/ send event with message \"hello!\", id current millis\n  \/\/ and set reconnect delay to 1 second\n  client-&gt;send(\"hello!\", NULL, millis(), 10000);\n );\n  server.addHandler(&amp;events);<\/code><\/pre>\n\n\n\n<p>Finally, start the server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.begin();<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">loop()<\/h3>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">loop()<\/span>, send a ping every 5 seconds. This is used to check on the client side, if the server is still running.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>static unsigned long lastEventTime = millis();\nstatic const unsigned long EVENT_INTERVAL_MS = 5000;\nif ((millis() - lastEventTime) &gt; EVENT_INTERVAL_MS) {\n  events.send(\"ping\",NULL,millis());\n  lastEventTime = millis();\n}<\/code><\/pre>\n\n\n\n<p>The following diagram summarizes how the Server-sent Events work on this project and how it updates the values without refreshing the web page. <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"928\" height=\"828\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP-NOW-Web-Server-with-Server-Sent-Events.png?resize=928%2C828&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 ESP-NOW Web Server Sensor Dashboard Project Overview\" class=\"wp-image-96750\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP-NOW-Web-Server-with-Server-Sent-Events.png?w=928&amp;quality=100&amp;strip=all&amp;ssl=1 928w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP-NOW-Web-Server-with-Server-Sent-Events.png?resize=300%2C268&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP-NOW-Web-Server-with-Server-Sent-Events.png?resize=768%2C685&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 928px) 100vw, 928px\" \/><\/figure><\/div>\n\n\n<p>After uploading the code to the receiver board, press the on-board EN\/RST button. The ESP32 IP address should be printed on the Serial Monitor as well as the Wi-Fi channel.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"669\" height=\"413\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/08\/ESP-NOW-IP-Address-Wi-Fi-channel-Serial-Monitor.png?resize=669%2C413&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP-NOW get ESP32 IP address and Wi-Fi channel\" class=\"wp-image-98799\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/08\/ESP-NOW-IP-Address-Wi-Fi-channel-Serial-Monitor.png?w=669&amp;quality=100&amp;strip=all&amp;ssl=1 669w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/08\/ESP-NOW-IP-Address-Wi-Fi-channel-Serial-Monitor.png?resize=300%2C185&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 669px) 100vw, 669px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">ESP32 Sender Circuit<\/h2>\n\n\n\n<p>The ESP32 sender boards are connected to a <a rel=\"noreferrer noopener\" href=\"https:\/\/makeradvisor.com\/tools\/dht22-temperature-humidity-sensor\/\" target=\"_blank\">DHT22 temperature and humidity sensor<\/a>. The data pin is connected to <span class=\"rnthl rntcblue\">GPIO 4<\/span>. You can choose any other suitable GPIO (<a href=\"https:\/\/randomnerdtutorials.com\/esp32-pinout-reference-gpios\/\">read ESP32 Pinout Guide<\/a>). Follow the next schematic diagram to wire the circuit.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"714\" height=\"892\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/04\/dht_esp32_bb.png?resize=714%2C892&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Wiring ESP32 to DHT22 temperature and humidity sensor\" class=\"wp-image-84352\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/04\/dht_esp32_bb.png?w=714&amp;quality=100&amp;strip=all&amp;ssl=1 714w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/04\/dht_esp32_bb.png?resize=240%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 240w\" sizes=\"(max-width: 714px) 100vw, 714px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">ESP32 Sender Code (ESP-NOW)<\/h2>\n\n\n\n<p>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.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"880\" height=\"605\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP-NOW-Send-Sensor-Readings-Structures-ESP32.png?resize=880%2C605&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Sender Receiver Board with ESP-NOW using Arduino IDE\" class=\"wp-image-96724\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP-NOW-Send-Sensor-Readings-Structures-ESP32.png?w=880&amp;quality=100&amp;strip=all&amp;ssl=1 880w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP-NOW-Send-Sensor-Readings-Structures-ESP32.png?resize=300%2C206&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP-NOW-Send-Sensor-Readings-Structures-ESP32.png?resize=768%2C528&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 880px) 100vw, 880px\" \/><\/figure><\/div>\n\n\n<p>Upload the following code to each of your sender boards. Don\u2019t forget to increment the&nbsp;<span class=\"rnthl rntliteral\">id<\/span>&nbsp;number for each sender board and insert your SSID in the <span class=\"rnthl rntliteral\">WIFI_SSID<\/span> variable.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*\n  Rui Santos &amp; Sara Santos - Random Nerd Tutorials\n  Complete project details at https:\/\/RandomNerdTutorials.com\/esp32-esp-now-wi-fi-web-server\/\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.\n  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\/\n#include &lt;esp_now.h&gt;\n#include &lt;esp_wifi.h&gt;\n#include &lt;WiFi.h&gt;\n#include &lt;Adafruit_Sensor.h&gt;\n#include &lt;DHT.h&gt;\n\n\/\/ Set your Board ID (ESP32 Sender #1 = BOARD_ID 1, ESP32 Sender #2 = BOARD_ID 2, etc)\n#define BOARD_ID 1\n\n\/\/ Digital pin connected to the DHT sensor\n#define DHTPIN 4  \n\n\/\/ Uncomment the type of sensor in use:\n\/\/#define DHTTYPE    DHT11     \/\/ DHT 11\n#define DHTTYPE    DHT22     \/\/ DHT 22 (AM2302)\n\/\/#define DHTTYPE    DHT21     \/\/ DHT 21 (AM2301)\n\nDHT dht(DHTPIN, DHTTYPE);\n\n\/\/MAC Address of the receiver \nuint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};\n\n\/\/Structure example to send data\n\/\/Must match the receiver structure\ntypedef struct struct_message {\n    int id;\n    float temp;\n    float hum;\n    int readingId;\n} struct_message;\n\nesp_now_peer_info_t peerInfo;\n\n\/\/Create a struct_message called myData\nstruct_message myData;\n\nunsigned long previousMillis = 0;   \/\/ Stores last time temperature was published\nconst long interval = 10000;        \/\/ Interval at which to publish sensor readings\n\nunsigned int readingId = 0;\n\n\/\/ Insert your SSID\nconstexpr char WIFI_SSID[] = &quot;REPLACE_WITH_YOUR_SSID&quot;;\n\nint32_t getWiFiChannel(const char *ssid) {\n  if (int32_t n = WiFi.scanNetworks()) {\n      for (uint8_t i=0; i&lt;n; i++) {\n          if (!strcmp(ssid, WiFi.SSID(i).c_str())) {\n              return WiFi.channel(i);\n          }\n      }\n  }\n  return 0;\n}\n\nfloat readDHTTemperature() {\n  \/\/ Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)\n  \/\/ Read temperature as Celsius (the default)\n  float t = dht.readTemperature();\n  \/\/ Read temperature as Fahrenheit (isFahrenheit = true)\n  \/\/float t = dht.readTemperature(true);\n  \/\/ Check if any reads failed and exit early (to try again).\n  if (isnan(t)) {    \n    Serial.println(&quot;Failed to read from DHT sensor!&quot;);\n    return 0;\n  }\n  else {\n    Serial.println(t);\n    return t;\n  }\n}\n\nfloat readDHTHumidity() {\n  \/\/ Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)\n  float h = dht.readHumidity();\n  if (isnan(h)) {\n    Serial.println(&quot;Failed to read from DHT sensor!&quot;);\n    return 0;\n  }\n  else {\n    Serial.println(h);\n    return h;\n  }\n}\n\n\/\/ callback when data is sent\nvoid OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {\n  Serial.print(&quot;\\r\\nLast Packet Send Status:\\t&quot;);\n  Serial.println(status == ESP_NOW_SEND_SUCCESS ? &quot;Delivery Success&quot; : &quot;Delivery Fail&quot;);\n}\n \nvoid setup() {\n  \/\/Init Serial Monitor\n  Serial.begin(115200);\n\n  dht.begin();\n \n  \/\/ Set device as a Wi-Fi Station and set channel\n  WiFi.mode(WIFI_STA);\n\n  int32_t channel = getWiFiChannel(WIFI_SSID);\n\n  WiFi.printDiag(Serial); \/\/ Uncomment to verify channel number before\n  esp_wifi_set_promiscuous(true);\n  esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);\n  esp_wifi_set_promiscuous(false);\n  WiFi.printDiag(Serial); \/\/ Uncomment to verify channel change after\n\n  \/\/ Init ESP-NOW\n  if (esp_now_init() != ESP_OK) {\n    Serial.println(&quot;Error initializing ESP-NOW&quot;);\n    return;\n  }\n\n  \/\/ Once ESPNow is successfully Init, we will register for Send CB to\n  \/\/ get the status of Trasnmitted packet\n  esp_now_register_send_cb(OnDataSent);\n  \n  \/\/ Register peer\n  memcpy(peerInfo.peer_addr, broadcastAddress, 6);\n  peerInfo.encrypt = false;\n  \n  \/\/ Add peer        \n  if (esp_now_add_peer(&amp;peerInfo) != ESP_OK){\n    Serial.println(&quot;Failed to add peer&quot;);\n    return;\n  }\n}\n \nvoid loop() {\n  unsigned long currentMillis = millis();\n  if (currentMillis - previousMillis &gt;= interval) {\n    \/\/ Save the last time a new reading was published\n    previousMillis = currentMillis;\n    \/\/Set values to send\n    myData.id = BOARD_ID;\n    myData.temp = readDHTTemperature();\n    myData.hum = readDHTHumidity();\n    myData.readingId = readingId++;\n     \n    \/\/Send message via ESP-NOW\n    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &amp;myData, sizeof(myData));\n    if (result == ESP_OK) {\n      Serial.println(&quot;Sent with success&quot;);\n    }\n    else {\n      Serial.println(&quot;Error sending the data&quot;);\n    }\n  }\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/ESP_NOW_WiFi\/ESP_NOW_Sender.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How the Code Works<\/h3>\n\n\n\n<p>Start by importing the required libraries:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include &lt;esp_now.h&gt;\n#include &lt;esp_wifi.h&gt;\n#include &lt;WiFi.h&gt;\n#include &lt;Adafruit_Sensor.h&gt;\n#include &lt;DHT.h&gt;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Set Board ID<\/h4>\n\n\n\n<p>Define the ESP32 sender board ID, for example set BOARD_ID 1 for ESP32 Sender #1, etc&#8230;<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Set your Board ID (ESP32 Sender #1 = BOARD_ID 1, ESP32 Sender #2 = BOARD_ID 2, etc)\n#define BOARD_ID 1<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">DHT Sensor<\/h4>\n\n\n\n<p>Define the pin the DHT sensor is connected to. In our example, it is connected to <span class=\"rnthl rntcblue\">GPIO 4<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define DHTPIN 4<\/code><\/pre>\n\n\n\n<p>Select the DHT sensor type you&#8217;re using. We&#8217;re using the DHT22.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Uncomment the type of sensor in use:\n\/\/#define DHTTYPE    DHT11     \/\/ DHT 11\n#define DHTTYPE    DHT22     \/\/ DHT 22 (AM2302)\n\/\/#define DHTTYPE    DHT21     \/\/ DHT 21 (AM2301)<\/code><\/pre>\n\n\n\n<p>Create a <span class=\"rnthl rntliteral\">DHT<\/span> object on the pin and type defined earlier.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>DHT dht(DHTPIN, DHTTYPE);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Receiver&#8217;s MAC Address<\/h4>\n\n\n\n<p>Insert the receiver&#8217;s MAC address on the next line (for example):<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>uint8_t broadcastAddress&#091;] = {0x30, 0xAE, 0xA4, 0x15, 0xC7, 0xFC};<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Data Structure<\/h4>\n\n\n\n<p>Then, create a structure that contains the data we want to send. The <span class=\"rnthl rntliteral\">struct_message<\/span> contains the board ID, temperature reading, humidity reading, and the reading ID.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>typedef struct struct_message {\n    int id;\n    float temp;\n    float hum;\n    int readingId;\n} struct_message;<\/code><\/pre>\n\n\n\n<p>Create a new variable of type <span class=\"rnthl rntliteral\">struct_message<\/span> that is called <span class=\"rnthl rntliteral\">myData<\/span> that stores the variables&#8217; values.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>struct_message myData;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Timer Interval<\/h4>\n\n\n\n<p>Create some auxiliary timer variables to publish the readings every 10 seconds. You can change the delay time on the <span class=\"rnthl rntliteral\">interval<\/span> variable.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>unsigned long previousMillis = 0;  \/\/ Stores last time temperature was published\nconst long interval = 10000;       \/\/ Interval at which to publish sensor readings<\/code><\/pre>\n\n\n\n<p>Initialize the <span class=\"rnthl rntliteral\">readingId<\/span> variable &#8211; it keeps track of the number of readings sent.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>unsigned int readingId = 0;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Changing Wi-Fi channel<\/h4>\n\n\n\n<p>Now, we&#8217;ll get the receiver&#8217;s Wi-Fi channel. This is useful because it allows us to automatically assign the same Wi-Fi channel to the sender board.<\/p>\n\n\n\n<p>To do that, you must insert your SSID in the following line:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>constexpr char WIFI_SSID&#091;] = \"REPLACE_WITH_YOUR_SSID\";<\/code><\/pre>\n\n\n\n<p>Then, the <span class=\"rnthl rntliteral\">getWiFiChannel()<\/span> function scans for your network and gets its channel.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>int32_t getWiFiChannel(const char *ssid) {\n  if (int32_t n = WiFi.scanNetworks()) {\n    for (uint8_t i=0; i&lt;n; i++) {\n      if (!strcmp(ssid, WiFi.SSID(i).c_str())) {\n        return WiFi.channel(i);\n      }\n    }\n  }\n  return 0;\n}<\/code><\/pre>\n\n\n\n<p><em>This snippet of code was proposed by Stephane (one of our readers). You can see his complete example <a href=\"https:\/\/github.com\/m1cr0lab-esp32\/esp-now-network-and-wifi-gateway\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/em><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Reading Temperature<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">readDHTTemperature()<\/span> function reads and returns the temperature from the DHT sensor. In case it is not able to get temperature readings, it returns <span class=\"rnthl rntliteral\">0<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>float readDHTTemperature() {\n  \/\/ Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)\n  \/\/ Read temperature as Celsius (the default)\n  float t = dht.readTemperature();\n  \/\/ Read temperature as Fahrenheit (isFahrenheit = true)\n  \/\/float t = dht.readTemperature(true);\n  \/\/ Check if any reads failed and exit early (to try again).\n  if (isnan(t)) {\n    Serial.println(\"Failed to read from DHT sensor!\");\n    return 0;\n  }\n  else {\n    Serial.println(t);\n    return t;\n  }\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Reading Humidity<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">readDHTHumidity()<\/span> function reads and returns the humidity from the DHT sensor. In case it is not able to get humidity readings, it returns <span class=\"rnthl rntliteral\">0<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>float readDHTHumidity() {\n  \/\/ Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)\n  float h = dht.readHumidity();\n  if (isnan(h)) {\n    Serial.println(\"Failed to read from DHT sensor!\");\n    return 0;\n  }\n  else {\n    Serial.println(h);\n    return h;\n  }\n}<\/code><\/pre>\n\n\n\n<p class=\"rntbox rntclblue\"><strong>Note: <\/strong> to learn more about getting temperature and humidity from the DHT22 or DHT11 sensors, read: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-dht11-dht22-temperature-humidity-sensor-arduino-ide\/\">ESP32 with DHT11\/DHT22 Temperature and Humidity Sensor using Arduino IDE<\/a>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">OnDataSent Callback Function<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">OnDataSent()<\/span> callback function will be executed when a message is sent. In this case, this function prints if the message was successfully delivered or not.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {\n  Serial.print(\"\\r\\nLast Packet Send Status:\\t\");\n  Serial.println(status == ESP_NOW_SEND_SUCCESS ? \"Delivery Success\" : \"Delivery Fail\");\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">setup()<\/h4>\n\n\n\n<p>Initialize the Serial Monitor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.begin(115200);<\/code><\/pre>\n\n\n\n<p>Set the ESP32 as a Wi-Fi station.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>WiFi.mode(WIFI_STA);<\/code><\/pre>\n\n\n\n<p>Set its channel to match the receiver&#8217;s Wi-Fi channel:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>int32_t channel = getWiFiChannel(WIFI_SSID);\n\nWiFi.printDiag(Serial); \/\/ Uncomment to verify channel number before\nesp_wifi_set_promiscuous(true);\nesp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);\nesp_wifi_set_promiscuous(false);\nWiFi.printDiag(Serial); \/\/ Uncomment to verify channel change after<\/code><\/pre>\n\n\n\n<p>Initialize ESP-NOW.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (esp_now_init() != ESP_OK) {\n  Serial.println(\"Error initializing ESP-NOW\");\n  return;\n}<\/code><\/pre>\n\n\n\n<p>After successfully initializing ESP-NOW, register the callback function that will be called when a message is sent. In this case, register for the <span class=\"rnthl rntliteral\">OnDataSent()<\/span> function created previously.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>esp_now_register_send_cb(OnDataSent);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Add peer<\/h4>\n\n\n\n<p>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.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Register peer\nmemcpy(peerInfo.peer_addr, broadcastAddress, 6);\npeerInfo.encrypt = false;\n\n\/\/ Add peer\nif (esp_now_add_peer(&amp;peerInfo) != ESP_OK){\n  Serial.println(\"Failed to add peer\");\n  return;\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">loop()<\/h4>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">loop()<\/span>, check if it is time to get and send new readings.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>unsigned long currentMillis = millis();\nif (currentMillis - previousMillis &gt;= interval) {\n  \/\/ Save the last time a new reading was published\n  previousMillis = currentMillis;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Send ESP-NOW Message<\/h4>\n\n\n\n<p>Finally, send the message structure via ESP-NOW.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Send message via ESP-NOW\nesp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &amp;myData, sizeof(myData));\nif (result == ESP_OK) {\n  Serial.println(\"Sent with success\");\n}\nelse {\n  Serial.println(\"Error sending the data\");\n}<\/code><\/pre>\n\n\n\n<p><strong>Recommended reading:<\/strong> <a rel=\"noreferrer noopener\" href=\"https:\/\/randomnerdtutorials.com\/esp-now-esp32-arduino-ide\/\" target=\"_blank\">Getting Started with ESP-NOW (ESP32 with Arduino IDE)<\/a><\/p>\n\n\n\n<p>Upload the code to your sender boards. You should notice that the boards change their Wi-Fi channel to the channel of the receiver board. In our case, the boards changed their Wi-Fi channel number to 6.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"669\" height=\"413\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/08\/Change-Wi-Fi-Cahnnel-ESP-NOW-ESP32.png?resize=669%2C413&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" class=\"wp-image-98800\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/08\/Change-Wi-Fi-Cahnnel-ESP-NOW-ESP32.png?w=669&amp;quality=100&amp;strip=all&amp;ssl=1 669w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/08\/Change-Wi-Fi-Cahnnel-ESP-NOW-ESP32.png?resize=300%2C185&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 669px) 100vw, 669px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Demonstration<\/h2>\n\n\n\n<p>After uploading the code to all the boards and if everything is going as expected, the ESP32 receiver board should start receiving sensor readings from the other boards.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP32-ESP-NOW-Web-Server-Sensor-Dashboard-ESP-NOW-Wi-Fi-Demonstration-Sensor-Readings.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 ESP-NOW Web Server Sensor Dashboard ESP-NOW and Wi-Fi Demonstration Sensor Readings\" class=\"wp-image-96914\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP32-ESP-NOW-Web-Server-Sensor-Dashboard-ESP-NOW-Wi-Fi-Demonstration-Sensor-Readings.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP32-ESP-NOW-Web-Server-Sensor-Dashboard-ESP-NOW-Wi-Fi-Demonstration-Sensor-Readings.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>Open a browser on your local network and type the ESP32 IP address. <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"917\" height=\"630\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP-NOW-Receiver-Web-Server-ESP32.png?resize=917%2C630&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 ESP-NOW Web Server Sensor Dashboard Web Browser\" class=\"wp-image-96748\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP-NOW-Receiver-Web-Server-ESP32.png?w=917&amp;quality=100&amp;strip=all&amp;ssl=1 917w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP-NOW-Receiver-Web-Server-ESP32.png?resize=300%2C206&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP-NOW-Receiver-Web-Server-ESP32.png?resize=768%2C528&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 917px) 100vw, 917px\" \/><\/figure><\/div>\n\n\n<p>It should load the temperature, humidity, and reading IDs for each board. Upon receiving a new packet, your web page updates automatically without refreshing the web page.<\/p>\n\n\n<div class=\"wp-block-image is-resized\">\n<figure class=\"aligncenter size-medium\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"204\" height=\"300\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP32-ESP-NOW-Web-Server-Sensor-Modile-Responsive-Dashboard.png?resize=204%2C300&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 ESP-NOW Web Server Sensor Dashboard Mobile Responsive\" class=\"wp-image-96918\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP32-ESP-NOW-Web-Server-Sensor-Modile-Responsive-Dashboard.png?resize=204%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 204w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP32-ESP-NOW-Web-Server-Sensor-Modile-Responsive-Dashboard.png?w=507&amp;quality=100&amp;strip=all&amp;ssl=1 507w\" sizes=\"(max-width: 204px) 100vw, 204px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>In this tutorial, you&#8217;ve learned how to use ESP-NOW and Wi-Fi to set up a web server to receive ESP-NOW packets from multiple boards (many-to-one configuration).<\/p>\n\n\n\n<p>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.<\/p>\n\n\n\n<p>We hope you like this project. Other projects\/tutorials you may like:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp-now-esp32-arduino-ide\/\">Getting Started with ESP-NOW (ESP32 with Arduino IDE)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp-now-one-to-many-esp32-esp8266\/\">ESP-NOW with ESP32: Send Data to Multiple Boards (one-to-many)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp-now-many-to-one-esp32\/\">ESP-NOW with ESP32: Receive Data from Multiple Boards (many-to-one)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp-now-two-way-communication-esp32\/\">ESP-NOW Two-Way Communication Between ESP32 Boards<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-lora-sensor-web-server\/\">ESP32 LoRa Sensor Monitoring with Web Server (Long Range Communication)<\/a><\/li>\n<\/ul>\n\n\n\n<p>Learn more about the ESP32 with our resources:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><a href=\"https:\/\/randomnerdtutorials.com\/learn-esp32-with-arduino-ide\/\">Learn ESP32 with Arduino IDE (eBook + video course)<\/a><\/strong><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/micropython-programming-with-esp32-and-esp8266\/\">MicroPython Programming with Arduino IDE<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-esp32\/\">More ESP32 tutorials &#8230;<\/a><\/li>\n<\/ul>\n\n\n\n<p class=\"rntbox rntclgray\"><em>We would like to thank our readers who helped us improve this tutorial, namely St\u00e9phane Calderoni and Lee Davidson for their valuable input. Thank you.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this project, you&#8217;ll learn how to host an ESP32 web server and use ESP-NOW communication protocol simultaneously. You can have several ESP32 boards sending sensor readings via ESP-NOW to &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP32: ESP-NOW Web Server Sensor Dashboard (ESP-NOW + Wi-Fi)\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp32-esp-now-wi-fi-web-server\/#more-96436\" aria-label=\"Read more about ESP32: ESP-NOW Web Server Sensor Dashboard (ESP-NOW + Wi-Fi)\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":5,"featured_media":96913,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[281,276,277,299,264],"tags":[],"class_list":["post-96436","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp32-project","category-esp32","category-esp32-arduino-ide","category-0-esp32","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/05\/ESP32-ESP-NOW-Web-Server-Sensor-Dashboard-ESP-NOW-Wi-Fi.jpg?fit=1280%2C720&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/96436","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=96436"}],"version-history":[{"count":6,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/96436\/revisions"}],"predecessor-version":[{"id":167951,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/96436\/revisions\/167951"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/96913"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=96436"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=96436"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=96436"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}