{"id":171725,"date":"2025-07-10T13:23:01","date_gmt":"2025-07-10T13:23:01","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=171725"},"modified":"2025-07-23T14:16:48","modified_gmt":"2025-07-23T14:16:48","slug":"esp32-cyd-esp-now-receive-data","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp32-cyd-esp-now-receive-data\/","title":{"rendered":"ESP32 CYD with ESP-NOW: Receive and Display Data From Multiple Boards"},"content":{"rendered":"\n<p>In this project, you&#8217;ll learn how to use the ESP-NOW communication protocol with the ESP32 CYD Board (Cheap Yellow Display) to receive and display data from multiple ESP32 sender boards. Two ESP32 boards will each read sensor data from a BME280 and send it to the CYD board. The CYD board, acting as the ESP-NOW receiver, will display the received data in separate tables\u2014one for each sender\u2014each shown on a different tab on the screen.<\/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\/2025\/06\/CYD-with-MicroPython-Receive-Data-From-Multiple-Boards.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 CYD with ESP-NOW: Receive and Display Data From Multiple Boards\" class=\"wp-image-171829\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/CYD-with-MicroPython-Receive-Data-From-Multiple-Boards.jpg?w=1920&amp;quality=100&amp;strip=all&amp;ssl=1 1920w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/CYD-with-MicroPython-Receive-Data-From-Multiple-Boards.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/CYD-with-MicroPython-Receive-Data-From-Multiple-Boards.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/CYD-with-MicroPython-Receive-Data-From-Multiple-Boards.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/CYD-with-MicroPython-Receive-Data-From-Multiple-Boards.jpg?resize=1536%2C864&amp;quality=100&amp;strip=all&amp;ssl=1 1536w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntclblue\"><strong>New to the ESP32 Cheap Yellow Display?<\/strong> Start here: <a href=\"https:\/\/randomnerdtutorials.com\/cheap-yellow-display-esp32-2432s028r\/\">Getting Started with ESP32 Cheap Yellow Display Board \u2013 CYD (ESP32-2432S028R)<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Project Overview<\/h2>\n\n\n\n<p>Here&#8217;s an overview of how this project works.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"750\" height=\"490\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/CYD-Receive-Data-Via-ESP-NOW-Project-Overview-.png?resize=750%2C490&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 CYD Board Receive Data from Multiple ESP32 Boards via ESP-NOW - project overview\" class=\"wp-image-171822\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/CYD-Receive-Data-Via-ESP-NOW-Project-Overview-.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/CYD-Receive-Data-Via-ESP-NOW-Project-Overview-.png?resize=300%2C196&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<ul class=\"wp-block-list\">\n<li>In this project, the ESP32 CYD board will act as a ESP-NOW receiver that receives data from other ESP32 boards.<\/li>\n\n\n\n<li>The other ESP32 boards will be sending sensor data (BME280) to the CYD board periodically, via ESP-NOW.<\/li>\n\n\n\n<li>The CYD board displays two tabs, each one for each board. Each tab contains a table with the data received from the other boards.<\/li>\n\n\n\n<li>The tables are updated as soon as the CYD receives new data.<\/li>\n<\/ul>\n\n\n\n<p class=\"rntbox rntclgray\"><strong>New to ESP-NOW communication protocol?<\/strong> Get started here: <a href=\"https:\/\/randomnerdtutorials.com\/esp-now-esp32-arduino-ide\/\">Getting Started with ESP-NOW (ESP32 with Arduino IDE)<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<p>Before proceeding, make sure you follow the next prerequisites.<strong> You must follow all steps, otherwise, your project will not work.<\/strong><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1) Parts Required<\/h3>\n\n\n\n<p>For this project, you need the following parts:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/cyd-cheap-yellow-display-esp32-2432s028r\/\" target=\"_blank\" rel=\"noopener\" title=\"\">ESP32 Cheap Yellow Display Board<\/a><\/li>\n\n\n\n<li>2x ESP32 boards of your choice (we&#8217;re using the <a href=\"https:\/\/makeradvisor.com\/tools\/esp32-dev-board-wi-fi-bluetooth\/\" target=\"_blank\" rel=\"noopener\" title=\"\">DOIT DevKIT V1 Board<\/a>)<\/li>\n\n\n\n<li>2x <a href=\"https:\/\/makeradvisor.com\/tools\/bme280-sensor-module\/\" target=\"_blank\" rel=\"noopener\" title=\"\">BME280<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/jumper-wires-kit-120-pieces\/\" target=\"_blank\" rel=\"noopener\" title=\"\">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<h3 class=\"wp-block-heading\">2) Install ESP32 Boards in Arduino IDE<\/h3>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"204\" height=\"204\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/arduino-ide-2.jpg?resize=204%2C204&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Arduino IDE 2 Logo\" class=\"wp-image-159109\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/arduino-ide-2.jpg?w=204&amp;quality=100&amp;strip=all&amp;ssl=1 204w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/arduino-ide-2.jpg?resize=150%2C150&amp;quality=100&amp;strip=all&amp;ssl=1 150w\" sizes=\"(max-width: 204px) 100vw, 204px\" \/><\/figure><\/div>\n\n\n<p>We&#8217;ll program the ESP32 using Arduino IDE. Make sure you have the ESP32 boards installed. Follow the next tutorial:<\/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 2 (Windows, Mac OS X, Linux)<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">3) Get familiar with the ESP32 Cheap Yellow Display<\/h3>\n\n\n\n<p>The&nbsp;<a href=\"https:\/\/makeradvisor.com\/tools\/cyd-cheap-yellow-display-esp32-2432s028r\/\" target=\"_blank\" rel=\"noreferrer noopener\">ESP32-2432S028R<\/a>&nbsp;development board has become known in the maker community as the \u201c<em>Cheap Yellow Display<\/em>\u201d or CYD for short. This development board, whose main chip is an ESP32-WROOM-32 module, comes with a 2.8-inch TFT touchscreen LCD, a microSD card interface, an RGB LED, and all the required circuitry to program and apply power to the board.<\/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=\"421\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/ESP32-Cheap-Yellow-Display-CYD-Board-ESP32-2432S028R-front.jpg?resize=750%2C421&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Cheap Yellow Display CYD Board ESP32-2432S028R front\" class=\"wp-image-149592\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/ESP32-Cheap-Yellow-Display-CYD-Board-ESP32-2432S028R-front.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/ESP32-Cheap-Yellow-Display-CYD-Board-ESP32-2432S028R-front.jpg?resize=300%2C168&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>If this is your first time using the ESP32 Cheap Yellow Display, make sure to follow our getting started guide:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/lvgl-cheap-yellow-display-esp32-2432s028r\/\">Getting Started with ESP32 Cheap Yellow Display Board and LVGL<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">4) Install TFT and LVGL Libraries<\/h3>\n\n\n\n<p><a href=\"https:\/\/docs.lvgl.io\/master\/\" target=\"_blank\" rel=\"noreferrer noopener\">LVGL<\/a>&nbsp;(Light and Versatile Graphics Library) is a free and open-source graphics library that provides a wide range of easy-to-use graphical elements for your microcontroller projects that require a graphical user interface (GUI).<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"622\" height=\"194\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/08\/LVGL-new-logo.png?resize=622%2C194&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"LVGL new logo\" class=\"wp-image-161339\" style=\"width:340px;height:auto\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/08\/LVGL-new-logo.png?w=622&amp;quality=100&amp;strip=all&amp;ssl=1 622w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/08\/LVGL-new-logo.png?resize=300%2C94&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 622px) 100vw, 622px\" \/><\/figure><\/div>\n\n\n<p>Follow the next tutorial to install and configure the required libraries to use LVGL for the ESP32 Cheap Yellow Display using Arduino IDE.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/lvgl-cheap-yellow-display-esp32-2432s028r\/\" title=\"\"><strong>Get started with LVGL using the ESP32 Cheap Yellow Display Board (ESP32-2432S028R)<\/strong><\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">5) Install BME280 Libraries<\/h3>\n\n\n\n<p>For this project, we&#8217;ll use the Adafruit BME280 library to get data from the BME280 on the other ESP32 boards. In the Arduino IDE, go to <strong>Sketch <\/strong>&gt; <strong>Include Library<\/strong> &gt; <strong>Manage Libraries<\/strong>. Search for <em>Adafruit BME280 Library<\/em> in the search box and install the library. Also, install any dependencies that are currently not installed (usually the Adafruit Bus IO and the Adafruit Unified Sensor libraries).<\/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=\"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\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Getting the CYD Board MAC Address<\/h2>\n\n\n\n<p>First, you need to know the MAC address of the CYD board so that the sender boards can send messages to it.<\/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=\"421\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/ESP32-Cheap-Yellow-Display-CYD-Board-ESP32-2432S028R-front.jpg?resize=750%2C421&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Cheap Yellow Display CYD Board ESP32-2432S028R front\" class=\"wp-image-149592\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/ESP32-Cheap-Yellow-Display-CYD-Board-ESP32-2432S028R-front.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/ESP32-Cheap-Yellow-Display-CYD-Board-ESP32-2432S028R-front.jpg?resize=300%2C168&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>Upload the following code to the CYD Board.<\/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#include &lt;WiFi.h&gt;\n#include &lt;esp_wifi.h&gt;\n\nvoid readMacAddress(){\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}\n\nvoid setup(){\n  Serial.begin(115200);\n\n  WiFi.mode(WIFI_STA);\n  WiFi.STA.begin();\n\n  Serial.print(&quot;[DEFAULT] ESP32 Board MAC Address: &quot;);\n  readMacAddress();\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\/ESP32\/ESP32_Get_MAC_Address.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>After uploading, open the Serial Monitor at a baud rate of 115200. Press the onboard RST button. The board&#8217;s MAC Address will be printed in 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=\"674\" height=\"394\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-CYD-Board-Get-Mac-Address.png?resize=674%2C394&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Getting the ESP32 CYD Board Mac Address on the Serial Monitor\" class=\"wp-image-171748\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-CYD-Board-Get-Mac-Address.png?w=674&amp;quality=100&amp;strip=all&amp;ssl=1 674w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-CYD-Board-Get-Mac-Address.png?resize=300%2C175&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 674px) 100vw, 674px\" \/><\/figure><\/div>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Preparing the Sender Boards<\/h2>\n\n\n\n<p>For this tutorial, we&#8217;ll send data to the CYD from two different boards. You can modify this project to display data from more boards. <\/p>\n\n\n\n<p>Each board will be identified by an ID (a number that we&#8217;ll attribute to each board):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>ID=1 for board1<\/li>\n\n\n\n<li>ID=2 for board2<\/li>\n<\/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=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/Two-ESP32-Boards-with-BME280.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Two ESP32 Boards with a BME280 Sensor\" class=\"wp-image-171823\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/Two-ESP32-Boards-with-BME280.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/Two-ESP32-Boards-with-BME280.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<h3 class=\"wp-block-heading\">Wiring the BME280 Sensor<\/h3>\n\n\n\n<p>Each sender board will send environmental data from a BME280 sensor. Wire a BME280 sensor to each of your boards. We&#8217;ll use the ESP32 default I2C pins.<\/p>\n\n\n\n<p>Learn more about I2C with the ESP32:&nbsp;<a href=\"https:\/\/randomnerdtutorials.com\/esp32-i2c-communication-arduino-ide\/\">ESP32 I2C Communication: Set Pins, Multiple Bus Interfaces and Peripherals (Arduino IDE)<\/a>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"675\" height=\"670\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-BME280-Sensor-Temperature-Humidity-Pressure-Wiring-Diagram-Circuit_f.png?resize=675%2C670&amp;quality=100&amp;strip=all&amp;ssl=1\" alt=\"ESP32 BME280 Sensor Temperature Humidity Pressure Wiring Diagram Circuit\" class=\"wp-image-99755\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-BME280-Sensor-Temperature-Humidity-Pressure-Wiring-Diagram-Circuit_f.png?w=675&amp;quality=100&amp;strip=all&amp;ssl=1 675w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-BME280-Sensor-Temperature-Humidity-Pressure-Wiring-Diagram-Circuit_f.png?resize=300%2C298&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-BME280-Sensor-Temperature-Humidity-Pressure-Wiring-Diagram-Circuit_f.png?resize=150%2C150&amp;quality=100&amp;strip=all&amp;ssl=1 150w\" sizes=\"(max-width: 675px) 100vw, 675px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntclgray\">Not familiar with the BME280 with the ESP32? Read this tutorial:&nbsp;<a href=\"https:\/\/randomnerdtutorials.com\/esp32-bme280-arduino-ide-pressure-temperature-humidity\/\"><strong>ESP32 with BME280 Sensor using Arduino IDE (Pressure, Temperature, Humidity)<\/strong><\/a>.<\/p>\n\n\n\n<p>If you&#8217;re using a different board model, the default I2C pins migh different.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">ESP32 ESP-NOW Sender Code<\/h3>\n\n\n\n<p>The following code reads the data from the BME280 sensor and sends it via ESP-NOW to the CYD board. Don&#8217;t forget to modify the code with your CYD board&#8217;s MAC address. Additionally, don&#8217;t forget to change the board ID for each of your 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-cyd-esp-now-receive-data\/\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 &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 1\n\nAdafruit_BME280 bme; \n\n\/\/ REPLACE WITH YOUR ESP RECEIVER'S MAC ADDRESS\nuint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};\n\n\/\/ Structure to send data, 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\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\nesp_now_peer_info_t peerInfo;\n\n\/\/ Callback when data is sent\nvoid OnDataSent(const wifi_tx_info_t* mac_addr, esp_now_send_status_t status) {\n  char macStr[18];\n  Serial.print(&quot;Packet to: &quot;);\n  \/\/ Copies the receiver mac address to a string\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.print(macStr);\n  Serial.print(&quot; 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  Serial.begin(115200);\n  initBME(); \n\n  WiFi.mode(WIFI_STA);\n \n  if (esp_now_init() != ESP_OK) {\n    Serial.println(&quot;Error initializing ESP-NOW&quot;);\n    return;\n  }\n  \n  esp_now_register_send_cb(esp_now_send_cb_t(OnDataSent));\n   \n  \/\/ Register peer\n  peerInfo.channel = 0;  \n  peerInfo.encrypt = false;\n  \/\/ Copy receiver's MAC address to peerInfo\n  memcpy(peerInfo.peer_addr, broadcastAddress, 6);\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 = readTemperature();\n    myData.hum = readHumidity();\n    myData.readingId = readingId++;\n     \n    \/\/ Send data and check for errors\n    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &amp;myData, sizeof(myData));\n    Serial.print(&quot;Sending data (Reading ID: &quot;);\n    Serial.print(myData.readingId);\n    Serial.print(&quot;, Temp: &quot;);\n    Serial.print(myData.temp);\n    Serial.print(&quot;C, Hum: &quot;);\n    Serial.print(myData.hum);\n    Serial.print(&quot;%): &quot;);\n    Serial.println(result == ESP_OK ? &quot;Sent&quot; : &quot;Failed to send&quot;);\n  }\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-TFT-Touchscreen\/raw\/main\/examples\/ESP32_ESP_NOW_Sender_BME280\/ESP32_ESP_NOW_Sender_BME280.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How Does the Code Work?<\/h3>\n\n\n\n<p>Let&#8217;s take a look at how the code works. If you&#8217;re new to ESP-NOW, we recommend <a href=\"https:\/\/randomnerdtutorials.com\/esp-now-esp32-arduino-ide\/\" title=\"\">getting started with this ESP-NOW guide<\/a> to better understand how things work.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Including Libraries<\/h4>\n\n\n\n<p>Start to include the required libraries for this project. The <span class=\"rnthl rntliteral\">esp_now<\/span> and <span class=\"rnthl rntliteral\">WiFi<\/span> are required to use ESP-NOW communication, and the <span class=\"rnthl rntliteral\">Adafruit_BME280<\/span> and <span class=\"rnthl rntliteral\">Adafruit_Sensor<\/span> are needed to interface with the BME280 sensor.<\/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 &lt;Adafruit_BME280.h&gt;\n#include &lt;Adafruit_Sensor.h&gt;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Set Your Board ID<\/h4>\n\n\n\n<p>Give a unique ID to your board so that the receiver can easily identify it. Here, we&#8217;re just numbering the boards, but you can use a different method, like giving them a name, or simply identifying them by the MAC address.<\/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 2<\/code><\/pre>\n\n\n\n<p>Make sure you give a different ID to each board.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">BME280 Instance<\/h4>\n\n\n\n<p>Create an instance of the <span class=\"rnthl rntliteral\">Adafruit_BME280<\/span> library called <span class=\"rnthl rntliteral\">bme<\/span> that will be used to interface with the sensor.<\/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\">The Receiver Board&#8217;s MAC Address<\/h4>\n\n\n\n<p>Insert your receiver board (the CYD board) MAC address. For example, my CYD board MAC address is <span class=\"rnthl rntliteral\">24:dc:c3:49:6a:14<\/span>. I must add it to the code in the following format.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ REPLACE WITH YOUR ESP RECEIVER'S MAC ADDRESS\nuint8_t broadcastAddress&#091;] = {0x24, 0xDC, 0xC3, 0x49, 0x6A, 0x14};<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Creating a Data Structure<\/h4>\n\n\n\n<p>Create a new structure called <span class=\"rnthl rntliteral\">struct_message<\/span> that will contain all the data you want to send. The <span class=\"rnthl rntliteral\">id<\/span> is the ID of the board, the <span class=\"rnthl rntliteral\">temperature<\/span> and <span class=\"rnthl rntliteral\">humidity<\/span> correspond to the data we get from the BME280 sensor, and the <span class=\"rnthl rntliteral\">readingId<\/span> is just a number to keep track of the number of readings sent.<\/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>Then, we create a new structure variable called <span class=\"rnthl rntliteral\">myData<\/span> based on the <span class=\"rnthl rntliteral\">struct_message<\/span> structure.<\/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\">Initializing and Getting Data from the BME280 Sensor<\/h4>\n\n\n\n<p>We create several functions related to the BME280 sensor.<\/p>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">initBME()<\/span> initializes the BME280 sensor on the ESP32&#8217;s default I2C pins.<\/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<p>The <span class=\"rnthl rntliteral\">readTemperature()<\/span> function returns the current temperature value as a float.<\/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<p>The <span class=\"rnthl rntliteral\">readHumidity()<\/span> function returns the current humidity value, also as a float.<\/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<h4 class=\"wp-block-heading\">Peer Info Variable<\/h4>\n\n\n\n<p>Create a new global variable of type <span class=\"rnthl rntliteral\">esp_now_peer_info_t<\/span> called <span class=\"rnthl rntliteral\">peerInfo<\/span> that will be used later on to save data about ESP-NOW peers.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>esp_now_peer_info_t peerInfo;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">OnDataSent()<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">onDataSent()<\/span> is a callback function that will be called when we send a message via ESP-NOW. This function will print the sender MAC address and whether the message was successfully delivered or not.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Callback when data is sent\nvoid OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {\n  char macStr&#091;18];\n  Serial.print(\"Packet to: \");\n  \/\/ Copies the receiver mac address to a string\n  snprintf(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]);\n  Serial.print(macStr);\n  Serial.print(\" 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>In the <span class=\"rnthl rntliteral\">setup()<\/span>, initialize the Serial Monitor and the BME280 sensor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.begin(115200);\ninitBME();<\/code><\/pre>\n\n\n\n<p>You also need to initialize the Wi-Fi interface to be able to use ESP-NOW.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>WiFi.mode(WIFI_STA);<\/code><\/pre>\n\n\n\n<p>Initialize ESP-NOW protocol.<\/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 a callback function that will run when we send data via ESP-NOW.<\/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<p>Register the ESP-NOW peer (the receiver board).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Register peer\npeerInfo.channel = 0;  \npeerInfo.encrypt = false;\n\/\/ Copy receiver's MAC address to peerInfo\nmemcpy(peerInfo.peer_addr, broadcastAddress, 6);\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<p>In this example, we won&#8217;t encrypt the messages. If you want to learn more about encrypting ESP-NOW messages, you can read this tutorial: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-esp-now-encrypted-messages\/\">ESP32: ESP-NOW Encrypted Messages<\/a>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">loop()<\/h4>\n\n\n\n<p>Finally, in the <span class=\"rnthl rntliteral\">loop()<\/span>, every 10 seconds (set previously on the <span class=\"rnthl rntliteral\">interval<\/span> variable), we get new data and set the <span class=\"rnthl rntliteral\">myData<\/span> structure values to that new data.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void 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++;<\/code><\/pre>\n\n\n\n<p>In the end, we use the <span class=\"rnthl rntliteral\">esp_now_send()<\/span> function to send the data to the peer.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Send data and check for errors\nesp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &amp;myData, sizeof(myData));<\/code><\/pre>\n\n\n\n<p>We print the sensor readings and information about the sending process in the Serial Monitor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &amp;myData, sizeof(myData));\nSerial.print(\"Sending data (Reading ID: \");\nSerial.print(myData.readingId);\nSerial.print(\", Temp: \");\nSerial.print(myData.temp);\nSerial.print(\"C, Hum: \");\nSerial.print(myData.hum);\nSerial.print(\"%): \");\nSerial.println(result == ESP_OK ? \"Sent\" : \"Failed to send\");<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Testing the Sender Code<\/h3>\n\n\n\n<p>After uploading the code to the board, open the Serial Monitor at a baud rate of 115200.<\/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\/2025\/06\/ESP32-BME280-ESP-NOW-Sender-Board-Serial-Monitor-Demonstration.png?quality=100&#038;strip=all&#038;ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"687\" height=\"381\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-BME280-ESP-NOW-Sender-Board-Serial-Monitor-Demonstration.png?resize=687%2C381&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Serial Monitor for the ESP32 ESP-NOW Sender Board - showing the message was sent, but delivery failed\" class=\"wp-image-171749\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-BME280-ESP-NOW-Sender-Board-Serial-Monitor-Demonstration.png?w=687&amp;quality=100&amp;strip=all&amp;ssl=1 687w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-BME280-ESP-NOW-Sender-Board-Serial-Monitor-Demonstration.png?resize=300%2C166&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 687px) 100vw, 687px\" \/><\/a><\/figure><\/div>\n\n\n<p>You&#8217;ll see that the board will start sending data via ESP-NOW. At the moment, the delivery is failing because we haven&#8217;t prepared the receiver yet\u2014that&#8217;s what we&#8217;re going to do next.<\/p>\n\n\n\n<p>Don&#8217;t forget to upload that code to each board and change the board ID.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">ESP32 CYD ESP-NOW Receiver Board<\/h2>\n\n\n\n<p>The CYD board will act as a ESP-NOW receiver that will get the data from the other two boards.<\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\"><div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"460\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-CYD-Board-Display-Data-Form-Multiple-Boards-ESP-NOW-1-small.png?resize=750%2C460&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 CYD Board Displaying data on a table - data received from other ESP32 via ESP-NOW\" class=\"wp-image-171820\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-CYD-Board-Display-Data-Form-Multiple-Boards-ESP-NOW-1-small.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-CYD-Board-Display-Data-Form-Multiple-Boards-ESP-NOW-1-small.png?resize=300%2C184&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div><\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\"><div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"460\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-CYD-Board-Display-Data-Form-Multiple-Boards-ESP-NOW-2-small.png?resize=750%2C460&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 CYD Board Displaying data on a table - data received from other ESP32 via ESP-NOW\" class=\"wp-image-171819\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-CYD-Board-Display-Data-Form-Multiple-Boards-ESP-NOW-2-small.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-CYD-Board-Display-Data-Form-Multiple-Boards-ESP-NOW-2-small.png?resize=300%2C184&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div><\/div>\n<\/div>\n\n\n\n<p>The data from each board will be displayed on the screen. We&#8217;ll create two different tabs: one for each board.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*  Rui Santos &amp; Sara Santos - Random Nerd Tutorials - https:\/\/RandomNerdTutorials.com\/esp32-cyd-esp-now-receive-data\/\n    THIS EXAMPLE WAS TESTED WITH THE FOLLOWING HARDWARE:\n    1) ESP32-2432S028R 2.8 inch 240\u00d7320 also known as the Cheap Yellow Display (CYD): https:\/\/makeradvisor.com\/tools\/cyd-cheap-yellow-display-esp32-2432s028r\/\n      SET UP INSTRUCTIONS: https:\/\/RandomNerdTutorials.com\/cyd-lvgl\/\n    2) REGULAR ESP32 Dev Board + 2.8 inch 240x320 TFT Display: https:\/\/makeradvisor.com\/tools\/2-8-inch-ili9341-tft-240x320\/ and https:\/\/makeradvisor.com\/tools\/esp32-dev-board-wi-fi-bluetooth\/\n      SET UP INSTRUCTIONS: https:\/\/RandomNerdTutorials.com\/esp32-tft-lvgl\/\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\/*  Install the &quot;lvgl&quot; library version 9.X by kisvegabor to interface with the TFT Display - https:\/\/lvgl.io\/\n    *** IMPORTANT: lv_conf.h available on the internet will probably NOT work with the examples available at Random Nerd Tutorials ***\n    *** YOU MUST USE THE lv_conf.h FILE PROVIDED IN THE LINK BELOW IN ORDER TO USE THE EXAMPLES FROM RANDOM NERD TUTORIALS ***\n    FULL INSTRUCTIONS AVAILABLE ON HOW CONFIGURE THE LIBRARY: https:\/\/RandomNerdTutorials.com\/cyd-lvgl\/ or https:\/\/RandomNerdTutorials.com\/esp32-tft-lvgl\/   *\/\n#include &lt;lvgl.h&gt;\n\n\/*  Install the &quot;TFT_eSPI&quot; library by Bodmer to interface with the TFT Display - https:\/\/github.com\/Bodmer\/TFT_eSPI\n    *** IMPORTANT: User_Setup.h available on the internet will probably NOT work with the examples available at Random Nerd Tutorials ***\n    *** YOU MUST USE THE User_Setup.h FILE PROVIDED IN THE LINK BELOW IN ORDER TO USE THE EXAMPLES FROM RANDOM NERD TUTORIALS ***\n    FULL INSTRUCTIONS AVAILABLE ON HOW CONFIGURE THE LIBRARY: https:\/\/RandomNerdTutorials.com\/cyd-lvgl\/ or https:\/\/RandomNerdTutorials.com\/esp32-tft-lvgl\/   *\/\n#include &lt;TFT_eSPI.h&gt;\n\n\/\/ Install the &quot;XPT2046_Touchscreen&quot; library by Paul Stoffregen to use the Touchscreen - https:\/\/github.com\/PaulStoffregen\/XPT2046_Touchscreen - Note: this library doesn't require further configuration\n#include &lt;XPT2046_Touchscreen.h&gt;\n\n#include &lt;esp_now.h&gt;\n#include &lt;WiFi.h&gt;\n#include &lt;freertos\/queue.h&gt;\n\n\/\/ Touchscreen pins\n#define XPT2046_IRQ 36   \/\/ T_IRQ\n#define XPT2046_MOSI 32  \/\/ T_DIN\n#define XPT2046_MISO 39  \/\/ T_OUT\n#define XPT2046_CLK 25   \/\/ T_CLK\n#define XPT2046_CS 33    \/\/ T_CS\n\nSPIClass touchscreenSPI = SPIClass(VSPI);\nXPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);\n\n#define SCREEN_WIDTH 240\n#define SCREEN_HEIGHT 320\n\n\/\/ SET VARIABLE TO 0 FOR THE TEMPERATURE DEGREES SYMBOL IN FAHRENHEIT\n#define TEMP_CELSIUS 1  \n\n\/\/ Touchscreen coordinates: (x, y) and pressure (z)\nint x, y, z;\n\n#define DRAW_BUF_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT \/ 10 * (LV_COLOR_DEPTH \/ 8))\nuint32_t draw_buf[DRAW_BUF_SIZE \/ 4];\n\n\/\/ Define a queue handle\nQueueHandle_t esp_now_queue;\n\n\/\/ Structure to receive data, must match the sender structure\ntypedef struct {\n    int id;\n    float temp;\n    float hum;\n    int readingId;\n} struct_message;\n\nstatic lv_obj_t * table1;\nstatic lv_obj_t * table2;\n\n\/\/ Callback function executed when data is received\nvoid OnDataRecv(const esp_now_recv_info *recv_info, const uint8_t *incomingData, int len) {\n  \/\/ Copy incoming data to myData structure\n  struct_message myData;\n  memcpy(&amp;myData, incomingData, sizeof(myData));\n  xQueueSendFromISR(esp_now_queue, &amp;myData, NULL); \/\/ Send to queue from ISR\n\n  \/\/ Get sender's MAC address from recv_info\n  const uint8_t *mac_addr = recv_info-&gt;src_addr;\n  \n  \/\/ Convert sender's MAC address to a string for display\n  char macStr[18];\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  \n  \/\/ Print received data to Serial Monitor\n  Serial.println(&quot;Received data:&quot;);\n  Serial.print(&quot;  Sender MAC: &quot;);\n  Serial.println(macStr);\n  Serial.print(&quot;  Board ID: &quot;);\n  Serial.println(myData.id);\n  Serial.print(&quot;  Temperature: &quot;);\n  Serial.print(myData.temp);\n  Serial.println(&quot; \u00b0C&quot;);\n  Serial.print(&quot;  Humidity: &quot;);\n  Serial.print(myData.hum);\n  Serial.println(&quot; %&quot;);\n  Serial.print(&quot;  Reading ID: &quot;);\n  Serial.println(myData.readingId);\n  Serial.println(&quot;-------------------&quot;);\n}\n\n\/\/ If logging is enabled, it will inform the user about what is happening in the library\nvoid log_print(lv_log_level_t level, const char * buf) {\n  LV_UNUSED(level);\n  Serial.println(buf);\n  Serial.flush();\n}\n\n\/\/ Get the Touchscreen data\nvoid touchscreen_read(lv_indev_t * indev, lv_indev_data_t * data) {\n  \/\/ Checks if Touchscreen was touched, and prints X, Y and Pressure (Z)\n  if(touchscreen.tirqTouched() &amp;&amp; touchscreen.touched()) {\n    \/\/ Get Touchscreen points\n    TS_Point p = touchscreen.getPoint();\n\n    \/\/ Advanced Touchscreen calibration, LEARN MORE \u00bb https:\/\/RandomNerdTutorials.com\/touchscreen-calibration\/\n    float alpha_x, beta_x, alpha_y, beta_y, delta_x, delta_y;\n\n    \/\/ REPLACE WITH YOUR OWN CALIBRATION VALUES \u00bb https:\/\/RandomNerdTutorials.com\/touchscreen-calibration\/\n    alpha_x = -0.000;\n    beta_x = 0.090;\n    delta_x = -33.771;\n    alpha_y = 0.066;\n    beta_y = 0.000;\n    delta_y = -14.632;\n\n    x = alpha_y * p.x + beta_y * p.y + delta_y;\n    \/\/ clamp x between 0 and SCREEN_WIDTH - 1\n    x = max(0, x);\n    x = min(SCREEN_WIDTH - 1, x);\n\n    y = alpha_x * p.x + beta_x * p.y + delta_x;\n    \/\/ clamp y between 0 and SCREEN_HEIGHT - 1\n    y = max(0, y);\n    y = min(SCREEN_HEIGHT - 1, y);\n\n    \/\/ Basic Touchscreen calibration points with map function to the correct width and height\n    \/\/x = map(p.x, 200, 3700, 1, SCREEN_WIDTH);\n    \/\/y = map(p.y, 240, 3800, 1, SCREEN_HEIGHT);\n\n    z = p.z;\n\n    data-&gt;state = LV_INDEV_STATE_PRESSED;\n\n    \/\/ Set the coordinates\n    data-&gt;point.x = x;\n    data-&gt;point.y = y;\n\n    \/\/ Print Touchscreen info about X, Y and Pressure (Z) on the Serial Monitor\n    Serial.print(&quot;X = &quot;);\n    Serial.print(x);\n    Serial.print(&quot; | Y = &quot;);\n    Serial.print(y);\n    Serial.print(&quot; | Pressure = &quot;);\n    Serial.print(z);\n    Serial.println();\n  }\n  else {\n    data-&gt;state = LV_INDEV_STATE_RELEASED;\n  }\n}\n\nvoid lv_create_main_gui(void) {\n  \/\/ Create a Tab view object\n  lv_obj_t * tabview;\n  tabview = lv_tabview_create(lv_screen_active());\n  lv_tabview_set_tab_bar_size(tabview, 40);\n  \n  \/\/ Add 3 tabs (the tabs are page (lv_page) and can be scrolled\n  lv_obj_t * tab1 = lv_tabview_add_tab(tabview, &quot;BOARD #1&quot;);\n  lv_obj_t * tab2 = lv_tabview_add_tab(tabview, &quot;BOARD #2&quot;);\n\n  table1 = lv_table_create(tab1);\n  lv_table_set_cell_value(table1, 0, 0, &quot;Temperature&quot;);\n  lv_table_set_cell_value(table1, 1, 0, &quot;Humidity&quot;);\n  lv_table_set_cell_value(table1, 2, 0, &quot;Reading ID&quot;);\n  lv_table_set_cell_value(table1, 0, 1, &quot;--&quot;);\n  lv_table_set_cell_value(table1, 1, 1, &quot;--&quot;);\n  lv_table_set_cell_value(table1, 2, 1, &quot;--&quot;);\n\n  table2 = lv_table_create(tab2);\n  lv_table_set_cell_value(table2, 0, 0, &quot;Temperature&quot;);\n  lv_table_set_cell_value(table2, 1, 0, &quot;Humidity&quot;);\n  lv_table_set_cell_value(table2, 2, 0, &quot;Reading ID&quot;);\n  lv_table_set_cell_value(table2, 0, 1, &quot;--&quot;);\n  lv_table_set_cell_value(table2, 1, 1, &quot;--&quot;);\n  lv_table_set_cell_value(table2, 2, 1, &quot;--&quot;);\n\n  \/\/ Center the tables\n  lv_obj_center(table1);\n  lv_obj_center(table2);\n}\n\nvoid update_table_values(struct_message *myData) {\n  #if TEMP_CELSIUS\n    const char degree_symbol[] = &quot;\\u00B0C&quot;;\n  #else\n    const char degree_symbol[] = &quot;\\u00B0F&quot;;\n  #endif\n\n  String temp_value = String(myData-&gt;temp) + degree_symbol;\n  String humi_value = String(myData-&gt;hum) + &quot;%&quot;;\n\n  if(myData-&gt;id == 1) {\n    lv_table_set_cell_value(table1, 0, 1, temp_value.c_str());\n    lv_table_set_cell_value(table1, 1, 1, humi_value.c_str());\n    lv_table_set_cell_value(table1, 2, 1, String(myData-&gt;readingId).c_str());\n  }\n  else if(myData-&gt;id == 2) {\n    lv_table_set_cell_value(table2, 0, 1, temp_value.c_str());\n    lv_table_set_cell_value(table2, 1, 1, humi_value.c_str());\n    lv_table_set_cell_value(table2, 2, 1, String(myData-&gt;readingId).c_str());\n  }\n}\n\nvoid setup() {\n  String LVGL_Arduino = String(&quot;LVGL Library Version: &quot;) + lv_version_major() + &quot;.&quot; + lv_version_minor() + &quot;.&quot; + lv_version_patch();\n  Serial.begin(115200);\n  Serial.println(LVGL_Arduino);\n\n  \/\/ Set device as a Wi-Fi Station\n  WiFi.mode(WIFI_STA);\n\n  \/\/ Initialize ESP-NOW\n  if (esp_now_init() != ESP_OK) {\n    Serial.println(&quot;Error initializing ESP-NOW&quot;);\n    return;\n  }\n\n  \/\/ Start LVGL\n  lv_init();\n  \/\/ Register print function for debugging\n  lv_log_register_print_cb(log_print);\n\n  \/\/ Start the SPI for the touchscreen and init the touchscreen\n  touchscreenSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);\n  touchscreen.begin(touchscreenSPI);\n  \/\/ Set the Touchscreen rotation in landscape mode\n  \/\/ Note: in some displays, the touchscreen might be upside down, so you might need to set the rotation to 0: touchscreen.setRotation(0);\n  touchscreen.setRotation(2);\n\n  \/\/ Create a display object\n  lv_display_t * disp;\n  \/\/ Initialize the TFT display using the TFT_eSPI library\n  disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf));\n  lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270);\n  \n  \/\/ Initialize an LVGL input device object (Touchscreen)\n  lv_indev_t * indev = lv_indev_create();\n  lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);\n  \/\/ Set the callback function to read Touchscreen input\n  lv_indev_set_read_cb(indev, touchscreen_read);\n\n  \/\/ Function to draw the GUI\n  lv_create_main_gui();\n\n  \/\/ Register callback function to handle received data\n  esp_now_register_recv_cb(OnDataRecv);\n  \n  esp_now_queue = xQueueCreate(10, sizeof(struct_message)); \/\/ Queue for 10 messages\n  if (esp_now_queue == NULL) {\n    Serial.println(&quot;Error creating queue&quot;);\n    return;\n  }\n}\n\nvoid loop() {\n  lv_task_handler();  \/\/ let the GUI do its work\n  lv_tick_inc(5);     \/\/ tell LVGL how much time has passed\n  delay(5);           \/\/ let this time pass\n  \n  struct_message myData;\n  if (xQueueReceive(esp_now_queue, &amp;myData, 0) == pdTRUE) {\n    \/\/ Process and display the data\n    update_table_values(&amp;myData);\n  }\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-TFT-Touchscreen\/raw\/main\/examples\/ESP32_CYD_LVGL_ESP_NOW_Receiver\/ESP32_CYD_LVGL_ESP_NOW_Receiver.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p class=\"rntbox rntclgray\">We cover how to create tabs, text fields, buttons, and much more in our LVGL for the ESP32 eBook. Check it out here: <a href=\"https:\/\/randomnerdtutorials.com\/learn-lvgl-esp32-ebook\/\" title=\"\">Learn LVGL: Build GUIs for ESP32 Projects (eBook)<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How Does the Code Work?<\/h3>\n\n\n\n<p>Now, let&#8217;s take a quick look at how the code works, or skip to the demonstration section.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Including Libraries<\/h4>\n\n\n\n<p>In all your LVGL sketches, you need to include the <span class=\"rnthl rntliteral\">lvgl.h<\/span> and the <span class=\"rnthl rntliteral\">TFT_eSPI.h<\/span> libraries to display on the screen.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include &lt;lvgl.h&gt;\n#include &lt;TFT_eSPI.h&gt;<\/code><\/pre>\n\n\n\n<p>We also use the touchscreen to choose between tabs. So, we need to include the touchscreen library.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include &lt;XPT2046_Touchscreen.h&gt;<\/code><\/pre>\n\n\n\n<p>You need to include the <span class=\"rnthl rntliteral\">WiFi<\/span> and <span class=\"rnthl rntliteral\">esp_now<\/span> libraries to use ESP-NOW.<\/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;<\/code><\/pre>\n\n\n\n<p>In our code, we&#8217;ll use queues to receive data via ESP-NOW while updating the display simultaneously.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include &lt;freertos\/queue.h&gt;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Initialize Touchscreen<\/h4>\n\n\n\n<p>The following lines set the touchscreen pinout:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define XPT2046_IRQ 36\n#define XPT2046_MOSI 32\n#define XPT2046_MISO 39\n#define XPT2046_CLK 25\n#define XPT2046_CS 33<\/code><\/pre>\n\n\n\n<p>Create a <span class=\"rnthl rntliteral\">touchscreenSPI<\/span> and <span class=\"rnthl rntliteral\">touchscreen<\/span> instances:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>SPIClass touchscreenSPI = SPIClass(VSPI);\nXPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Defining the Display Width and Height<\/h4>\n\n\n\n<p>You need to define your display width and height in all your sketches that use LVGL. If you\u2019re using the recommended display, the size is 240&#215;320.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define SCREEN_WIDTH 240\n#define SCREEN_HEIGHT 320<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">X, Y, and Z Touchscreen Variables<\/h4>\n\n\n\n<p>Define the variables to hold the touch coordinates and touch pressure.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Touchscreen coordinates: (x, y) and pressure (z)\nint x, y, z;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Creating a Drawing Buffer<\/h4>\n\n\n\n<p>You need to create a buffer to draw on the display as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define DRAW_BUF_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT \/ 10 * (LV_COLOR_DEPTH \/ 8))\nuint32_t draw_buf&#091;DRAW_BUF_SIZE \/ 4];<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Create a Queue<\/h4>\n\n\n\n<p>Create a new queue called <span class=\"rnthl rntliteral\">esp_now_queue<\/span> that we&#8217;ll use later for handling the tasks for receiving ESP-NOW messages and updating the display.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Define a queue handle\nQueueHandle_t esp_now_queue;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Data Structure<\/h4>\n\n\n\n<p>Create a data structure to receive the data from the sender. This must be the same sent by the sender board.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Structure to receive data, must match the sender structure\ntypedef struct {\n    int id;\n    float temp;\n    float hum;\n    int readingId;\n} struct_message;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">LVGL Objects for the Tables<\/h4>\n\n\n\n<p>In this project, we&#8217;ll create two tables. One to display the data from each board. We&#8217;re creating two LVGL objects globally that will then be used to refer to the tables.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>static lv_obj_t * table1;\nstatic lv_obj_t * table2;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">onDataRecv() ESP-NOW Callback Function<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">onDataRecv()<\/span> function will run when the board receives new data via ESP-NOW.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Callback function executed when data is received\nvoid OnDataRecv(const esp_now_recv_info *recv_info, const uint8_t *incomingData, int len) {\n  \/\/ Copy incoming data to myData structure\n  struct_message myData;\n  memcpy(&amp;myData, incomingData, sizeof(myData));\n  xQueueSendFromISR(esp_now_queue, &amp;myData, NULL); \/\/ Send to queue from ISR\n\n  \/\/ Get sender's MAC address from recv_info\n  const uint8_t *mac_addr = recv_info-&gt;src_addr;\n  \n  \/\/ Convert sender's MAC address to a string for display\n  char macStr&#091;18];\n  snprintf(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]);\n  \n  \/\/ Print received data to Serial Monitor\n  Serial.println(\"Received data:\");\n  Serial.print(\"  Sender MAC: \");\n  Serial.println(macStr);\n  Serial.print(\"  Board ID: \");\n  Serial.println(myData.id);\n  Serial.print(\"  Temperature: \");\n  Serial.print(myData.temp);\n  Serial.println(\" \u00b0C\");\n  Serial.print(\"  Humidity: \");\n  Serial.print(myData.hum);\n  Serial.println(\" %\");\n  Serial.print(\"  Reading ID: \");\n  Serial.println(myData.readingId);\n  Serial.println(\"-------------------\");\n}<\/code><\/pre>\n\n\n\n<p>In this function, we get the received data and save it in the <span class=\"rnthl rntliteral\">myData<\/span> variable.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Copy incoming data to myData structure\nstruct_message myData;\nmemcpy(&amp;myData, incomingData, sizeof(myData));<\/code><\/pre>\n\n\n\n<p>Then, we send the <span class=\"rnthl rntliteral\">myData<\/span> variable to the queue in a safe way (non-blocking). <\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>xQueueSendFromISR(esp_now_queue, &amp;myData, NULL); \/\/ Send to queue from ISR<\/code><\/pre>\n\n\n\n<p>Basically, the function <span class=\"rnthl rntliteral\">xQueueSendFromISR(esp_now_queue, &amp;myData, NULL)<\/span> sends data (<span class=\"rnthl rntliteral\">myData<\/span>) to a FreeRTOS queue (<span class=\"rnthl rntliteral\">esp_now_queue<\/span>). Then, we&#8217;ll use this data on a function that display the sensor readings on the screen.<\/p>\n\n\n\n<p>Then, we print the received data in the Serial Monitor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.println(\"Received data:\");\nSerial.print(\"  Sender MAC: \");\nSerial.println(macStr);\nSerial.print(\"  Board ID: \");\nSerial.println(myData.id);\nSerial.print(\"  Temperature: \");\nSerial.print(myData.temp);\nSerial.println(\" \u00b0C\");\nSerial.print(\"  Humidity: \");\nSerial.print(myData.hum);\nSerial.println(\" %\");\nSerial.print(\"  Reading ID: \");\nSerial.println(myData.readingId);\nSerial.println(\"-------------------\");<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Debugging Function<\/h4>\n\n\n\n<p>For debugging with the LVGL library, you should use the <span class=\"rnthl rntliteral\">log_print()<\/span> function. It is defined below. Include it in all your sketches before the <span class=\"rnthl rntliteral\">setup()<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ If logging is enabled, it will inform the user about what is happening in the library\nvoid log_print(lv_log_level_t level, const char * buf) {\n  LV_UNUSED(level);\n  Serial.println(buf);\n  Serial.flush();\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Touchscreen Callback Function<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">touchscreen_read()<\/span> callback function will be called when touch is detected on the touchscreen.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Get the Touchscreen data\nvoid touchscreen_read(lv_indev_t * indev, lv_indev_data_t * data) {\n  \/\/ Checks if Touchscreen was touched, and prints X, Y and Pressure (Z)\n  if(touchscreen.tirqTouched() &amp;&amp; touchscreen.touched()) {\n    \/\/ Get Touchscreen points\n    TS_Point p = touchscreen.getPoint();\n\n\n(....)\n  }\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">LVGL Main Function &#8211; Drawing the GUI<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">lv_create_main_gui()<\/span> function will draw the GUI on the display. This function will be called later in the <span class=\"rnthl rntliteral\">setup<\/span>.<\/p>\n\n\n\n<p>First, we create a <span class=\"rnthl rntliteral\">tabview<\/span> where we&#8217;ll add our tabs\u2014one tab for each board.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Create a Tab view object\nlv_obj_t * tabview;\ntabview = lv_tabview_create(lv_screen_active());\nlv_tabview_set_tab_bar_size(tabview, 40);<\/code><\/pre>\n\n\n\n<p>Then, we create the tabs we want to display and add them to the <span class=\"rnthl rntliteral\">tabview<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>lv_obj_t * tab1 = lv_tabview_add_tab(tabview, \"BOARD #1\");\nlv_obj_t * tab2 = lv_tabview_add_tab(tabview, \"BOARD #2\");<\/code><\/pre>\n\n\n\n<p>Then, we create a table called <span class=\"rnthl rntliteral\">table1<\/span> and add it to <span class=\"rnthl rntliteral\">tab1<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>table1 = lv_table_create(tab1);<\/code><\/pre>\n\n\n\n<p>After that, we create the cells for the table.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>lv_table_set_cell_value(table1, 0, 0, \"Temperature\");\nlv_table_set_cell_value(table1, 1, 0, \"Humidity\");\nlv_table_set_cell_value(table1, 2, 0, \"Reading ID\");\nlv_table_set_cell_value(table1, 0, 1, \"--\");\nlv_table_set_cell_value(table1, 1, 1, \"--\");\nlv_table_set_cell_value(table1, 2, 1, \"--\");<\/code><\/pre>\n\n\n\n<p>We follow a similar procedure for the other table.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>table2 = lv_table_create(tab2);\nlv_table_set_cell_value(table2, 0, 0, \"Temperature\");\nlv_table_set_cell_value(table2, 1, 0, \"Humidity\");\nlv_table_set_cell_value(table2, 2, 0, \"Reading ID\");\nlv_table_set_cell_value(table2, 0, 1, \"--\");\nlv_table_set_cell_value(table2, 1, 1, \"--\");\nlv_table_set_cell_value(table2, 2, 1, \"--\");<\/code><\/pre>\n\n\n\n<p>After creating the tables, we center them in the middle of the screen.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Center the tables\nlv_obj_center(table1);\nlv_obj_center(table2);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Update the Table<\/h4>\n\n\n\n<p>To update the values on the table, we&#8217;ll later call the <span class=\"rnthl rntliteral\">update_table_values()<\/span> function.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void update_table_values(struct_message *myData) {<\/code><\/pre>\n\n\n\n<p>We first check the board ID to determine from which board we received the data, and then update the corresponding table accordingly.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if(myData-&gt;id == 1) {\n  lv_table_set_cell_value(table1, 0, 1, temp_value.c_str());\n  lv_table_set_cell_value(table1, 1, 1, humi_value.c_str());\n  lv_table_set_cell_value(table1, 2, 1, String(myData-&gt;readingId).c_str());\n}\nelse if(myData-&gt;id == 2) {\n  lv_table_set_cell_value(table2, 0, 1, temp_value.c_str());\n  lv_table_set_cell_value(table2, 1, 1, humi_value.c_str());\n  lv_table_set_cell_value(table2, 2, 1, String(myData-&gt;readingId).c_str());\n}<\/code><\/pre>\n\n\n\n<p>To learn more about creating and handling tables in LVGL, you can check this project:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cyd-lvgl-display-bme280-data-table\/\">ESP32 CYD with LVGL: Display BME280 Sensor Data on a Table<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">setup()<\/h3>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">setup()<\/span>, include the following lines for debugging. These will print the version of LVGL that you\u2019re using. You must be using version 9.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>String LVGL_Arduino = String(\"LVGL Library Version: \") + lv_version_major() + \".\" + lv_version_minor() + \".\" + lv_version_patch();\nSerial.begin(115200);\nSerial.println(LVGL_Arduino);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Initialize ESP-NOW<\/h4>\n\n\n\n<p>Activate the Wi-Fi interface and initialize ESP-NOW.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Set device as a Wi-Fi Station\nWiFi.mode(WIFI_STA);\n\n\/\/ Initialize ESP-NOW\nif (esp_now_init() != ESP_OK) {\n  Serial.println(\"Error initializing ESP-NOW\");\n  return;\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Initialize the LVGL Library<\/h4>\n\n\n\n<p>Initialize the LVGL Library by calling the <span class=\"rnthl rntliteral\">lv_init()<\/span> function in the <span class=\"rnthl rntliteral\">setup()<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Start LVGL\nlv_init();<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Register Debugging Function<\/h4>\n\n\n\n<p>Register your <span class=\"rnthl rntliteral\">log_print()<\/span> function declared previously as a function associated with debugging LVGL.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Register print function for debugging\nlv_log_register_print_cb(log_print);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Start the Touchscreen<\/h4>\n\n\n\n<p>Start the SPI for the touchscreen and initialize the touchscreen.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>touchscreenSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);\ntouchscreen.begin(touchscreenSPI);\ntouchscreen.setRotation(2);<\/code><\/pre>\n\n\n\n<p><strong>Note:<\/strong> in some displays, the touchscreen might be upside down, so you might need to set the rotation to 0: <span class=\"rnthl rntliteral\">touchscreen.setRotation(0);<\/span><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Creating a Display Object<\/h4>\n\n\n\n<p>Create the display object and initialize the TFT display using the <span class=\"rnthl rntliteral\">TFT_eSPI<\/span> library.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>  \/\/ Create a display object\n  lv_display_t * disp;\n  \/\/ Initialize the TFT display using the TFT_eSPI library\n  disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf));\n  lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270);<\/code><\/pre>\n\n\n\n<p>Initialize an LVGL input device object (touchscreen) and set the callback function that will be triggered when you click the touchscreen\u2014the <span class=\"rnthl rntliteral\">touchscreen_read()<\/span> function we created previously.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Initialize an LVGL input device object (Touchscreen)\nlv_indev_t * indev = lv_indev_create();\nlv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);\n\/\/ Set the callback function to read Touchscreen input\nlv_indev_set_read_cb(indev, touchscreen_read);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Drawing the GUI<\/h4>\n\n\n\n<p>Call the <span class=\"rnthl rntliteral\">lv_create_main_gui()<\/span> function to draw the GUI for your touchscreen:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>lv_create_main_gui();<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">ESP-NOW Callback Function<\/h4>\n\n\n\n<p>Set which function to run when the board receives data via ESP-NOW. In this case, it will run the <span class=\"rnthl rntliteral\">OnDataRecv()<\/span> function that we&#8217;ve already created previously.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Register callback function to handle received data\nesp_now_register_recv_cb(OnDataRecv);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Creating a Queue<\/h4>\n\n\n\n<p>The code <span class=\"rnthl rntliteral\">esp_now_queue = xQueueCreate(10, sizeof(struct_message))<\/span> creates a FreeRTOS queue to hold up to 10 ESP-NOW messages of type <span class=\"rnthl rntliteral\">struct_message<\/span> for communication between an ISR (the ESP-NOW callback function) and a task.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>esp_now_queue = xQueueCreate(10, sizeof(struct_message)); \/\/ Queue for 10 messages\nif (esp_now_queue == NULL) {\n  Serial.println(\"Error creating queue\");\n  return;\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Updating the Table Values in the Loop<\/h4>\n\n\n\n<p>This line <span class=\"rnthl rntliteral\">if (xQueueReceive(esp_now_queue, &amp;myData, 0) == pdTRUE)<\/span> checks if a message is available in <span class=\"rnthl rntliteral\">esp_now_queue<\/span> without waiting, storing it in <span class=\"rnthl rntliteral\">myData<\/span> if successful. If a message is received, it calls <span class=\"rnthl rntliteral\">update_table_values(&amp;myData)<\/span> to process and display the data on the screen. <\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (xQueueReceive(esp_now_queue, &amp;myData, 0) == pdTRUE) {\n  \/\/ Process and display the data\n  update_table_values(&amp;myData);\n}<\/code><\/pre>\n\n\n\n<p>This method ensures that we don&#8217;t block the ESP-NOW callback function while writing to the display.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Demonstration<\/h2>\n\n\n\n<p>Upload the code to your CYD board. Go to&nbsp;<strong>Tools&nbsp;<\/strong>&gt;&nbsp;<strong>Board&nbsp;<\/strong>and select&nbsp;<strong>ESP32&nbsp;<\/strong>&gt;&nbsp;<strong>ESP32 Dev Module<\/strong>. Then, select the right COM port in&nbsp;<strong>Tools&nbsp;<\/strong>&gt;&nbsp;<strong>Port<\/strong>.<\/p>\n\n\n\n<p>Go to <strong>Tools <\/strong>&gt; <strong>Partition scheme<\/strong> &gt; choose anything that has more than 1.4MB APP, for example: &#8220;<strong>Huge APP (3MB No OTA\/1MB SPIFFS<\/strong>&#8220;.<\/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=\"768\" height=\"817\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/08\/Select-Huge-App-Partion-Scheme-Arduino-IDE-Tools-Menu.png?resize=768%2C817&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Select Huge App Partion Scheme Arduino IDE Tools Menu\" class=\"wp-image-161757\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/08\/Select-Huge-App-Partion-Scheme-Arduino-IDE-Tools-Menu.png?w=768&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/08\/Select-Huge-App-Partion-Scheme-Arduino-IDE-Tools-Menu.png?resize=282%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 282w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure><\/div>\n\n\n<p>Finally, click the upload button.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"36\" height=\"39\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/05\/arduino-ide-2-upload-button.png?resize=36%2C39&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Arduino IDE 2 Upload Button\" class=\"wp-image-146269\" style=\"width:36px;height:auto\"\/><\/figure><\/div>\n\n\n<p>After a few minutes, the CYD board will start receiving the messages from the sender boards via ESP-NOW.<\/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\/2025\/06\/ESP32-CYD-Board-Display-Data-Received-Via-ESP-NOW-Table.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 CYD Board Displaying Data received via ESP-NOW on a table\" class=\"wp-image-171765\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-CYD-Board-Display-Data-Received-Via-ESP-NOW-Table.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-CYD-Board-Display-Data-Received-Via-ESP-NOW-Table.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>The data received from each board will be displayed on a table. We divided the screen into two tabs. Each tab displays a table for each board.<\/p>\n\n\n\n<p>To change between tabs, you can swipe left\/right, or tap on the tab name at the top.<\/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\/2025\/06\/ESP32-CYD-Board-Swipe-Between-Tabs.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 CYD Board - Swiping between tabs\" class=\"wp-image-171766\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-CYD-Board-Swipe-Between-Tabs.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/ESP32-CYD-Board-Swipe-Between-Tabs.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<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>In this tutorial, you learned how to use <a href=\"https:\/\/randomnerdtutorials.com\/esp-now-esp32-arduino-ide\/\" title=\"\">ESP-NOW<\/a> with the <a href=\"https:\/\/randomnerdtutorials.com\/lvgl-cheap-yellow-display-esp32-2432s028r\/\" title=\"\">CYD board<\/a> to receive data from multiple ESP32 boards.<\/p>\n\n\n\n<p>In a similar way, you can also send data to multiple ESP32 boards. The CYD board can act like a remote control with buttons that control other boards wirelessly.<\/p>\n\n\n\n<p>We hope you found this tutorial useful. If you would like to learn more about creating graphical user interfaces using the LVGL library with the ESP32, check out our latest eBook:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><a href=\"https:\/\/randomnerdtutorials.com\/learn-lvgl-esp32-ebook\/\">Learn LVGL: Build GUIs for ESP32 Projects (eBook)<\/a><\/strong><\/li>\n<\/ul>\n\n\n\n<p>Other guides you might like reading:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/cheap-yellow-display-esp32-2432s028r\/\">Getting Started with ESP32 Cheap Yellow Display Board \u2013 CYD (ESP32-2432S028R)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/touchscreen-on-off-button-cheap-yellow-display-esp32-2432s028r\/\">ESP32 Touchscreen On\/Off Button \u2013 Cheap Yellow Display (ESP32-2432S028R)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cheap-yellow-display-cyd-pinout-esp32-2432s028r\/\">ESP32 Cheap Yellow Display (CYD) Pinout (ESP32-2432S028R)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/lvgl-cheap-yellow-display-esp32-2432s028r\/\">LVGL with ESP32 Cheap Yellow Display Board (ESP32-2432S028R)<\/a><\/li>\n<\/ul>\n\n\n\n<p>To learn more about the ESP32, make sure to take a look at our resources:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/learn-esp32-with-arduino-ide\/\">Learn ESP32 with Arduino IDE (eBook)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/smart-home-ebook\/\" title=\"\">SMART HOME with Raspberry Pi, ESP32, and ESP8266 eBook<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-esp32\/\" title=\"\"><strong>Free ESP32 Guides and Tutorials<\/strong><\/a><\/li>\n<\/ul>\n\n\n\n<p>Thanks for reading.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this project, you&#8217;ll learn how to use the ESP-NOW communication protocol with the ESP32 CYD Board (Cheap Yellow Display) to receive and display data from multiple ESP32 sender boards. &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP32 CYD with ESP-NOW: Receive and Display Data From Multiple Boards\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp32-cyd-esp-now-receive-data\/#more-171725\" aria-label=\"Read more about ESP32 CYD with ESP-NOW: Receive and Display Data From Multiple Boards\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":5,"featured_media":171829,"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":[276,281,277,299,264],"tags":[],"class_list":["post-171725","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp32","category-esp32-project","category-esp32-arduino-ide","category-0-esp32","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/CYD-with-MicroPython-Receive-Data-From-Multiple-Boards.jpg?fit=1920%2C1080&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/171725","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=171725"}],"version-history":[{"count":21,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/171725\/revisions"}],"predecessor-version":[{"id":174274,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/171725\/revisions\/174274"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/171829"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=171725"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=171725"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=171725"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}