{"id":100126,"date":"2020-11-25T14:23:23","date_gmt":"2020-11-25T14:23:23","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=100126"},"modified":"2025-03-17T11:40:35","modified_gmt":"2025-03-17T11:40:35","slug":"esp8266-esp-now-wi-fi-web-server","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp8266-esp-now-wi-fi-web-server\/","title":{"rendered":"ESP8266 NodeMCU: ESP-NOW Web Server Sensor Dashboard (ESP-NOW + Wi-Fi)"},"content":{"rendered":"\n<p>In this project you&#8217;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.<\/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\/11\/ESP8266-ESP-NOW-Web-Server-Sensor-Dashboard-ESP-NOW-Wi-Fi..jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 NodeMCU: ESP-NOW Web Server Sensor Dashboard using Arduino IDE (ESP-NOW and Wi-Fi simultaneously)\" class=\"wp-image-100143\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP8266-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\/11\/ESP8266-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\/11\/ESP8266-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\/11\/ESP8266-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-esp8266-nodemcu-arduino-ide\/\">Getting Started with ESP-NOW (ESP8266 NodeMCU with Arduino IDE)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp-now-two-way-communication-esp8266-nodemcu\/\">ESP-NOW Two-Way Communication Between ESP8266 NodeMCU Boards<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp-now-one-to-many-esp8266-nodemcu\/\">ESP-NOW with ESP8266: 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-esp8266-nodemcu\/\">ESP-NOW with ESP8266: Receive Data from Multiple Boards (many-to-one)<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Using ESP-NOW and Wi-Fi Simultaneously<\/h2>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"905\" height=\"887\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP8266-ESP-NOW-With-Wi-Fi-Web-Server-How-It-Works.png?resize=905%2C887&#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 with ESP8266 NodeMCU\" class=\"wp-image-100132\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP8266-ESP-NOW-With-Wi-Fi-Web-Server-How-It-Works.png?w=905&amp;quality=100&amp;strip=all&amp;ssl=1 905w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP8266-ESP-NOW-With-Wi-Fi-Web-Server-How-It-Works.png?resize=300%2C294&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP8266-ESP-NOW-With-Wi-Fi-Web-Server-How-It-Works.png?resize=768%2C753&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 905px) 100vw, 905px\" \/><\/figure><\/div>\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 class=\"wp-block-list\">\n<li>The ESP8266 sender boards must use the same Wi-Fi channel of the receiver board.<\/li>\n\n\n\n<li>The Wi-Fi channel of the receiver board is automatically assigned by your Wi-Fi router.<\/li>\n\n\n\n<li>The Wi-Fi mode of the receiver board must be access point and station (<span class=\"rnthl rntliteral\">WIFI_AP_STA<\/span>).<\/li>\n\n\n\n<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>\n<\/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=\"900\" height=\"806\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Web-Server-Receiver-Two-Sender-Board-how-it-works-ESP8266.png?resize=900%2C806&#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 using ESP8266 NodeMCU boards\" class=\"wp-image-100134\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Web-Server-Receiver-Two-Sender-Board-how-it-works-ESP8266.png?w=900&amp;quality=100&amp;strip=all&amp;ssl=1 900w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Web-Server-Receiver-Two-Sender-Board-how-it-works-ESP8266.png?resize=300%2C269&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Web-Server-Receiver-Two-Sender-Board-how-it-works-ESP8266.png?resize=768%2C688&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 900px) 100vw, 900px\" \/><\/figure><\/div>\n\n\n<ul class=\"wp-block-list\">\n<li>There are two ESP8266 sender boards that send <a href=\"https:\/\/makeradvisor.com\/tools\/bme280-sensor-module\/\" target=\"_blank\" rel=\"noreferrer noopener\">BME280<\/a> temperature and humidity readings via ESP-NOW to one ESP8266 receiver board (<a href=\"https:\/\/randomnerdtutorials.com\/esp-now-many-to-one-esp8266-nodemcu\/\">ESP-NOW many to one configuration<\/a>);<\/li>\n\n\n\n<li>The ESP8266 receiver board receives the packets and displays the readings on a web server;<\/li>\n\n\n\n<li>The web page is updated automatically every time it receives a new reading using Server-Sent Events (SSE). <\/li>\n\n\n\n<li>The web page also shows the last time the readings were updated using JavaScript.<\/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 ESP8266 boards using Arduino IDE, so before proceeding with this tutorial, make sure you have the ESP8266 board installed in your Arduino IDE.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/installing-esp8266-nodemcu-arduino-ide-2-0\/\" title=\"\">Installing ESP8266 Board in Arduino IDE (Windows, Mac OS X, and Linux)<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">BME280 Libraries<\/h3>\n\n\n\n<p>The ESP8266 sender board will send temperature and humidity readings from a BME280 sensor.<\/p>\n\n\n\n<p>To read from the BME280 sensor, we\u2019ll use the <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/adafruit\/Adafruit_BME280_Library\" target=\"_blank\">Adafruit_BME280 library<\/a>. To use this library you also need to install the&nbsp;<a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/adafruit\/Adafruit_Sensor\" target=\"_blank\">Adafruit Unified Sensor library<\/a>. Follow the next steps to install those libraries.<\/p>\n\n\n\n<p>Search for \u201cAdafruit BME280 Library\u201d in the Search box and install the library.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/09\/Installing-Adafruit-BME280-Sensor-Library-Arduino-IDE.png?quality=100&#038;strip=all&#038;ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"290\" height=\"305\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/09\/Installing-Adafruit-BME280-Sensor-Library-Arduino-IDE.png?resize=290%2C305&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Installing Adafruit BME280 Sensor Library Arduino IDE\" class=\"wp-image-162191\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/09\/Installing-Adafruit-BME280-Sensor-Library-Arduino-IDE.png?w=290&amp;quality=100&amp;strip=all&amp;ssl=1 290w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/09\/Installing-Adafruit-BME280-Sensor-Library-Arduino-IDE.png?resize=285%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 285w\" sizes=\"(max-width: 290px) 100vw, 290px\" \/><\/a><\/figure><\/div>\n\n\n<p>To use the BME280 library, you also need to install the\u00a0Adafruit_Sensor library. A pop-up window will ask you to install it and any other dependencies when you install the BME280 library.<\/p>\n\n\n\n<p class=\"rntbox rntclblue\">To learn more about the BME280 temperature, humidity and pressure sensor, read our guide: <a href=\"https:\/\/randomnerdtutorials.com\/esp8266-bme280-arduino-ide\/\">ESP8266 with BME280 using Arduino IDE (Pressure, Temperature, Humidity)<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Async Web Server Libraries<\/h3>\n\n\n\n<p>We&#8217;ll build the web server using the following libraries:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/ESP32Async\/ESPAsyncWebServer\" target=\"_blank\" rel=\"noopener\" title=\"\">ESPAsyncWebServer by ESP32Async<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/ESP32Async\/ESPAsyncTCP\" target=\"_blank\" rel=\"noopener\" title=\"\">ESPAsyncTCP&nbsp;by ESP32Async<\/a><\/li>\n<\/ul>\n\n\n\n<p>You can install these libraries using 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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Arduino_JSON Library<\/h3>\n\n\n\n<p>You need to install the <a href=\"https:\/\/github.com\/arduino-libraries\/Arduino_JSON\" target=\"_blank\" rel=\"noopener\" title=\"\">Arduino_JSON library<\/a>. You can install this library in the Arduino IDE Library Manager. Just go to\u00a0<strong>Sketch\u00a0<\/strong>>\u00a0<strong>Include Library<\/strong>\u00a0>\u00a0<strong>Manage Libraries<\/strong>\u00a0and search for the library name &#8220;Arduino_JSON&#8221;, and select the option <strong>by Arduino<\/strong>.<\/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 ESP8266 boards. We&#8217;ll use three ESP8266 boards. You also need:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>3x <a href=\"https:\/\/makeradvisor.com\/tools\/esp8266-esp-12e-nodemcu-wi-fi-development-board\/\" target=\"_blank\" rel=\"noreferrer noopener\">ESP8266\u00a0<\/a>(read\u00a0<a href=\"https:\/\/makeradvisor.com\/tools\/esp8266-esp-12e-nodemcu-wi-fi-development-board\/\" target=\"_blank\" rel=\"noreferrer noopener\">Best ESP8266 development boards<\/a>)<\/li>\n\n\n\n<li>2x <a href=\"https:\/\/makeradvisor.com\/tools\/esp8266-esp-12e-nodemcu-wi-fi-development-board\/\" target=\"_blank\" rel=\"noreferrer noopener\">BME280 sensor<\/a> &#8211; <a href=\"https:\/\/randomnerdtutorials.com\/esp8266-bme280-arduino-ide\/\">BME280 guide for ESP8266<\/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 ESP8266 MAC Address<\/a>).<\/p>\n\n\n\n<p>Upload the following code to your ESP8266 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\">ESP8266 Receiver (ESP-NOW + Web Server)<\/h2>\n\n\n\n<p>The ESP8266 NodeMCU 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\/esp8266-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\n#include &lt;espnow.h&gt;\n#include &lt;ESP8266WiFi.h&gt;\n#include &quot;ESPAsyncWebServer.h&quot;\n#include &quot;ESPAsyncTCP.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(uint8_t * mac_addr, uint8_t *incomingData, uint8_t 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    h1 {  font-size: 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(320px, 1fr)); }\n    .reading { font-size: 2.8rem; }\n    .timestamp { color: #bebebe; font-size: 1rem; }\n    .card-title{ font-size: 1.2rem; font-weight : bold; }\n    .card.temperature { color: #B10F2E; }\n    .card.humidity { color: #50B8B4; }\n  &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;div class=&quot;topnav&quot;&gt;\n    &lt;h1&gt;ESP-NOW DASHBOARD&lt;\/h1&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;p class=&quot;card-title&quot;&gt;&lt;i class=&quot;fas fa-thermometer-half&quot;&gt;&lt;\/i&gt; BOARD #1 - TEMPERATURE&lt;\/p&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;timestamp&quot;&gt;Last Reading: &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;p class=&quot;card-title&quot;&gt;&lt;i class=&quot;fas fa-tint&quot;&gt;&lt;\/i&gt; BOARD #1 - HUMIDITY&lt;\/p&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;timestamp&quot;&gt;Last Reading: &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;p class=&quot;card-title&quot;&gt;&lt;i class=&quot;fas fa-thermometer-half&quot;&gt;&lt;\/i&gt; BOARD #2 - TEMPERATURE&lt;\/p&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;timestamp&quot;&gt;Last Reading: &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;p class=&quot;card-title&quot;&gt;&lt;i class=&quot;fas fa-tint&quot;&gt;&lt;\/i&gt; BOARD #2 - HUMIDITY&lt;\/p&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;timestamp&quot;&gt;Last Reading: &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;\nfunction getDateTime() {\n  var currentdate = new Date();\n  var datetime = currentdate.getDate() + &quot;\/&quot;\n  + (currentdate.getMonth()+1) + &quot;\/&quot;\n  + currentdate.getFullYear() + &quot; at &quot;\n  + currentdate.getHours() + &quot;:&quot;\n  + currentdate.getMinutes() + &quot;:&quot;\n  + currentdate.getSeconds();\n  return datetime;\n}\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 = getDateTime();\n  document.getElementById(&quot;rh&quot;+obj.id).innerHTML = getDateTime();\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() != 0) {\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(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\/ESP8266\/ESP_NOW\/ESP_NOW_ESP8266_Web_Server_Receiver.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;espnow.h&gt;\n#include &lt;ESP8266WiFi.h&gt;\n#include \"ESPAsyncWebServer.h\"\n#include \"ESPAsyncTCP.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 ESP8266 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 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(uint8_t * mac_addr, uint8_t *incomingData, uint8_t len) { \n<\/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>char 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 on 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 ESP8266 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 = getDateTime();\ndocument.getElementById(\"rh\"+obj.id).innerHTML = getDateTime();<\/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. We also update the date and time the readings were received by calling the <span class=\"rnthl rntliteral\">getDateTime()<\/span> JavaScript function.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>function getDateTime() {\n  var currentdate = new Date();\n  var datetime = currentdate.getDate() + \"\/\"\n  + (currentdate.getMonth()+1) + \"\/\"\n  + currentdate.getFullYear() + \" at \"\n  + currentdate.getHours() + \":\"\n  + currentdate.getMinutes() + \":\"\n  + currentdate.getSeconds();\n  return datetime;\n}<\/code><\/pre>\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 ESP8266 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 ESP8266 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() != 0) {\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(OnDataRecv);<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Handle Requests<\/h3>\n\n\n\n<p>When you access the ESP8266 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);\nserver.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 (these lines are not mandatory).<\/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=\"937\" height=\"854\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Web-Server-with-Server-Sent-Events-ESP8266-NodeMCU.png?resize=937%2C854&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 ESP-NOW Web Server Sensor Dashboard Project Overview\" class=\"wp-image-100135\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Web-Server-with-Server-Sent-Events-ESP8266-NodeMCU.png?w=937&amp;quality=100&amp;strip=all&amp;ssl=1 937w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Web-Server-with-Server-Sent-Events-ESP8266-NodeMCU.png?resize=300%2C273&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Web-Server-with-Server-Sent-Events-ESP8266-NodeMCU.png?resize=768%2C700&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 937px) 100vw, 937px\" \/><\/figure><\/div>\n\n\n<p>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.<\/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\">ESP8266 Sender Circuit<\/h2>\n\n\n\n<p>The ESP8266 sender boards are connected to a BME280 sensor. Wire the sensor to the default ESP8266 I2C pins:<\/p>\n\n\n\n<ul><li><span class=\"rnthl rntcblue\">GPIO 5<\/span> (D1) -&gt; SCL<\/li><li><span class=\"rnthl rntcgreen\">GPIO 4<\/span> (D2) -&gt; SDA<\/li><\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"675\" height=\"531\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/07\/ESP8266-NodeMCU-BME280-Sensor-Temperature-Humidity-Pressure-Wiring-Diagram-Circuit.png?resize=675%2C531&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 NodeMCU BME280 Sensor Temperature Humidity Pressure Wiring Diagram Circuit\" class=\"wp-image-98049\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/07\/ESP8266-NodeMCU-BME280-Sensor-Temperature-Humidity-Pressure-Wiring-Diagram-Circuit.png?w=675&amp;quality=100&amp;strip=all&amp;ssl=1 675w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/07\/ESP8266-NodeMCU-BME280-Sensor-Temperature-Humidity-Pressure-Wiring-Diagram-Circuit.png?resize=300%2C236&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 675px) 100vw, 675px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">ESP8266 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=\"900\" height=\"643\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Send-Sensor-Readings-Structures-ESP8266.jpg?resize=900%2C643&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 Sender Receiver Board with ESP-NOW using Arduino IDE\" class=\"wp-image-100138\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Send-Sensor-Readings-Structures-ESP8266.jpg?w=900&amp;quality=100&amp;strip=all&amp;ssl=1 900w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Send-Sensor-Readings-Structures-ESP8266.jpg?resize=300%2C214&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Send-Sensor-Readings-Structures-ESP8266.jpg?resize=768%2C549&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 900px) 100vw, 900px\" \/><\/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\n  Complete project details at https:\/\/RandomNerdTutorials.com\/esp8266-esp-now-wi-fi-web-server\/\n  \n  Permission is hereby granted, free of charge, to any person obtaining a copy\n  of this software and associated documentation files.\n  \n  The above copyright notice and this permission notice shall be included in all\n  copies or substantial portions of the Software.\n*\/\n\n#include &lt;espnow.h&gt;\n#include &lt;ESP8266WiFi.h&gt;\n#include &lt;Adafruit_BME280.h&gt;\n#include &lt;Adafruit_Sensor.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 2\n\nAdafruit_BME280 bme; \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\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\nvoid initBME(){\n  if (!bme.begin(0x76)) {\n    Serial.println(&quot;Could not find a valid BME280 sensor, check wiring!&quot;);\n    while (1);\n  }\n}\n\nfloat readTemperature() {\n  float t = bme.readTemperature();\n  return t;\n}\n\nfloat readHumidity() {\n  float h = bme.readHumidity();\n  return h;\n}\n\n\/\/ Callback when data is sent\nvoid OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {\n  Serial.print(&quot;Last Packet Send Status: &quot;);\n  if (sendStatus == 0){\n    Serial.println(&quot;Delivery success&quot;);\n  }\n  else{\n    Serial.println(&quot;Delivery fail&quot;);\n  }\n}\n \nvoid setup() {\n  \/\/Init Serial Monitor\n  Serial.begin(115200);\n  initBME(); \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  wifi_promiscuous_enable(1);\n  wifi_set_channel(channel);\n  wifi_promiscuous_enable(0);\n  WiFi.printDiag(Serial); \/\/ Uncomment to verify channel change after\n\n  \/\/ Init ESP-NOW\n  if (esp_now_init() != 0) {\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_set_self_role(ESP_NOW_ROLE_CONTROLLER);\n\n  esp_now_register_send_cb(OnDataSent);\n  \n  esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);\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 = readTemperature();\n    myData.hum = readHumidity();\n    myData.readingId = readingId++;\n     \n    esp_now_send(broadcastAddress, (uint8_t *) &amp;myData, sizeof(myData));\n\n    Serial.print(&quot;loop&quot;);\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\/ESP8266\/ESP_NOW\/ESP_NOW_ESP8266_Web_Server_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;espnow.h&gt;\n#include &lt;ESP8266WiFi.h&gt;\n#include &lt;Adafruit_BME280.h&gt;\n#include &lt;Adafruit_Sensor.h&gt;\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Set Board ID<\/h4>\n\n\n\n<p>Define the ESP8266 sender board ID, for example set <span class=\"rnthl rntliteral\">BOARD_ID 1<\/span> for ESP8266 Sender #1, etc&#8230;<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define BOARD_ID 1<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">BME280 Sensor<\/h4>\n\n\n\n<p>Create an <span class=\"rnthl rntliteral\">Adafruit_BME280<\/span> object called <span class=\"rnthl rntliteral\">bme<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Adafruit_BME280 bme;<\/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\">Initialize BME280 Sensor<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">initBME()<\/span> function initializes the BME280 sensor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void initBME(){\n  if (!bme.begin(0x76)) {\n    Serial.println(\"Could not find a valid BME280 sensor, check wiring!\");\n    while (1);\n  }\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Reading Temperature<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">readTemperature()<\/span> function reads and returns the temperature from the BME280 sensor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>float readTemperature() {\n  float t = bme.readTemperature();\n  return t;\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\">readHumidity()<\/span> function reads and returns the humidity from the BME280 sensor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>float readHumidity() {\n  float h = bme.readHumidity();\n  return h;\n}<\/code><\/pre>\n\n\n\n<p class=\"rntbox rntclblue\"><strong>Note: <\/strong> to learn more about getting temperature and humidity from the BME280 sensor, read: <a href=\"https:\/\/randomnerdtutorials.com\/esp8266-bme280-arduino-ide\/\">ESP8266 with BME280 using Arduino IDE (Pressure, Temperature, Humidity)<\/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(uint8_t *mac_addr, uint8_t sendStatus) {\n  Serial.print(\"Last Packet Send Status: \");\n  if (sendStatus == 0){\n    Serial.println(\"Delivery success\");\n  }\n  else{\n    Serial.println(\"Delivery fail\");\n  }\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>Initialize the BME280 sensor:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>initBME();<\/code><\/pre>\n\n\n\n<p>Set the ESP8266 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\nwifi_promiscuous_enable(1);\nwifi_set_channel(channel);\nwifi_promiscuous_enable(0);\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>\/\/ Init ESP-NOW\nif (esp_now_init() != 0) {\n  Serial.println(\"Error initializing ESP-NOW\");\n  return;\n}<\/code><\/pre>\n\n\n\n<p>Set the ESP8266 role:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);<\/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>esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);<\/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>esp_now_send(broadcastAddress, (uint8_t *) &amp;myData, sizeof(myData));<\/code><\/pre>\n\n\n\n<p><strong>Recommended reading:<\/strong> <a href=\"https:\/\/randomnerdtutorials.com\/esp-now-esp8266-nodemcu-arduino-ide\/\">Getting Started with ESP-NOW (ESP8266 with Arduino IDE)<\/a><\/p>\n\n\n\n<p>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.<\/p>\n\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 ESP8266 receiver board should start receiving sensor readings from the other boards.<\/p>\n\n\n\n<p>Open a browser on your local network and type the ESP8266 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=\"944\" height=\"617\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Web-Server-ESP8266.png?resize=944%2C617&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 NodeMCU ESP-NOW Web Server Sensor Dashboard ESP-NOW and Wi-Fi Demonstration Sensor Readings\" class=\"wp-image-100139\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Web-Server-ESP8266.png?w=944&amp;quality=100&amp;strip=all&amp;ssl=1 944w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Web-Server-ESP8266.png?resize=300%2C196&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Web-Server-ESP8266.png?resize=768%2C502&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 944px) 100vw, 944px\" \/><\/figure><\/div>\n\n\n<p>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.<\/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=\"300\" height=\"600\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Web-Server-ESP8266-smartphone.jpg?resize=300%2C600&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP8266 NodeMCU ESP-NOW Web Server Sensor Dashboard Demo\" class=\"wp-image-100140\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Web-Server-ESP8266-smartphone.jpg?w=300&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP-NOW-Web-Server-ESP8266-smartphone.jpg?resize=150%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 150w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/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 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:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-esp-now-wi-fi-web-server\/\">ESP32: ESP-NOW Web Server Sensor Dashboard (ESP-NOW + Wi-Fi)<\/a><\/li>\n<\/ul>\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. We have a dedicated guide to Server-Sent Events:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp8266-nodemcu-web-server-sent-events-sse\/\">ESP8266 NodeMCU Web Server using Server-Sent Events (Update Sensor Readings Automatically)<\/a><\/li>\n<\/ul>\n\n\n\n<p>If you like ESP8266, you might consider enrolling in our eBook \u201c<a href=\"https:\/\/randomnerdtutorials.com\/home-automation-using-esp8266\/\">Home Automation using ESP8266<\/a>\u201c. You can also access our free&nbsp;<a href=\"https:\/\/randomnerdtutorials.com\/projects-esp8266\/\">ESP8266 resources here<\/a>.<\/p>\n\n\n\n<p>Thanks for reading.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this project you&#8217;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 &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP8266 NodeMCU: ESP-NOW Web Server Sensor Dashboard (ESP-NOW + Wi-Fi)\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp8266-esp-now-wi-fi-web-server\/#more-100126\" aria-label=\"Read more about ESP8266 NodeMCU: ESP-NOW Web Server Sensor Dashboard (ESP-NOW + Wi-Fi)\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":5,"featured_media":100143,"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":[265,214,300,240,264],"tags":[],"class_list":["post-100126","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp8266-project","category-esp8266","category-0-esp8266","category-esp8266-projects","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/11\/ESP8266-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\/100126","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=100126"}],"version-history":[{"count":2,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/100126\/revisions"}],"predecessor-version":[{"id":168064,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/100126\/revisions\/168064"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/100143"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=100126"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=100126"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=100126"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}