{"id":165008,"date":"2025-02-27T14:36:58","date_gmt":"2025-02-27T14:36:58","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=165008"},"modified":"2025-02-27T14:37:02","modified_gmt":"2025-02-27T14:37:02","slug":"esp32-tft-lvgl-line-chart","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp32-tft-lvgl-line-chart\/","title":{"rendered":"ESP32 TFT with LVGL: Display Temperature on Line Chart (BME280)"},"content":{"rendered":"\n<p>In this guide, you&#8217;ll learn how to display temperature from the BME280 sensor on an ESP32 and a TFT display using LVGL (Light Versatile Graphics Library). You\u2019ll learn how to draw a line chart to display data from a sensor. The ESP32 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\/2024\/12\/ESP32-TFT-Display-BME280-Line-Chart.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 TFT with LVGL: Display Temperature on Line Chart (BME280)\" class=\"wp-image-165010\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/ESP32-TFT-Display-BME280-Line-Chart.jpg?w=1920&amp;quality=100&amp;strip=all&amp;ssl=1 1920w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/ESP32-TFT-Display-BME280-Line-Chart.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/ESP32-TFT-Display-BME280-Line-Chart.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/ESP32-TFT-Display-BME280-Line-Chart.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/ESP32-TFT-Display-BME280-Line-Chart.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\">Are you using a CYD board? <a href=\"https:\/\/randomnerdtutorials.com\/esp32-cyd-lvgl-line-chart\/\" title=\"\">Read this guide: ESP32 CYD with LVGL: Display Temperature on Line Chart (BME280)<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Project Overview<\/h2>\n\n\n\n<p>In this project, we\u2019ll draw a line chart with the temperature from the BME280 sensor on the ESP32 with a TFT display. Here&#8217;s the main features:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The chart displays a maximum of 20 data points;<\/li>\n\n\n\n<li>When a new point is added to the screen, the oldest data point is deleted;<\/li>\n\n\n\n<li>The vertical axis range will adjust automatically depending on the current values plotted on the chart;<\/li>\n\n\n\n<li>You can touch next to the data points to check the precise value of a point\u2014it will draw a label with its value next to it.<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"750\" height=\"432\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/ESP32-TFT-Project-Overview-Line-Chart-BME280.png?resize=750%2C432&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 TFT Project Overview Line Chart BME280\" class=\"wp-image-164501\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/ESP32-TFT-Project-Overview-Line-Chart-BME280.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/ESP32-TFT-Project-Overview-Line-Chart-BME280.png?resize=300%2C173&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\">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\/2-8-inch-ili9341-tft-240x320\/\" target=\"_blank\" rel=\"noreferrer noopener\">TFT LCD Touchscreen Display \u2013 2.8 inch ILI9341 240\u00d7320<\/a><\/li>\n\n\n\n<li>ESP32 board with enough pins to wire the display (for example an <a href=\"https:\/\/makeradvisor.com\/tools\/esp32-dev-board-wi-fi-bluetooth\/\" target=\"_blank\" rel=\"noopener\" title=\"\">ESP32 DOIT V1 board<\/a>)<\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/bme280-sensor-module\/\" target=\"_blank\" rel=\"noopener\" title=\"\">BME280 Sensor<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/mb-102-solderless-breadboard-830-points\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Breadboard<\/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\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 ILI9341 TFT LCD Touchscreen Display<\/h3>\n\n\n\n<p>The display we\u2019re using in this guide is the 2.8. inch TFT LCD that also comes with a touchscreen. The display communicates via SPI communication protocol and uses the ILI9341 driver. The touchscreen also uses the SPI communication protocol.<\/p>\n\n\n\n<p>The TFT LCD touchscreen also comes with an SD card interface if you need to load files for your specific project. This display is also available with different screen sizes, but we&#8217;ll use the one with 240 x 320 pixels).<\/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\/TFT-LCD-Touchscreen-display.jpg?resize=750%2C421&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ILI9341 TFT LCD Touchscreen Display\" class=\"wp-image-150003\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/TFT-LCD-Touchscreen-display.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/TFT-LCD-Touchscreen-display.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 this display, make sure to follow our getting started guide:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><a href=\"https:\/\/randomnerdtutorials.com\/lvgl-esp32-tft-touchscreen-display-ili9341-arduino\/\" title=\"\">ESP32 with LVGL: TFT LCD Touchscreen Display \u2013 2.8 inch ILI9341 240\u00d7320 (Arduino IDE)<\/a><\/strong><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">4) Wire the Display to the ESP32<\/h3>\n\n\n\n<p>Wire the TFT LCD and touchscreen pins to the ESP32 GPIOs according to the next table (you must use these exact pins, otherwise the project will not work).<\/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\/2024\/03\/ESP32-TFT-Display-Screen-Wiring.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Wiring TFT LCD Touchscreen display to ESP32\" class=\"wp-image-150007\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/ESP32-TFT-Display-Screen-Wiring.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-TFT-Display-Screen-Wiring.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<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>TFT LCD Touchscreen<\/strong><\/td><td><strong>ESP32<\/strong><\/td><\/tr><tr><td>T_IRQ<\/td><td>GPIO 36<\/td><\/tr><tr><td>T_OUT<\/td><td>GPIO 39<\/td><\/tr><tr><td>T_DIN<\/td><td>GPIO 32<\/td><\/tr><tr><td>T_CS<\/td><td>GPIO 33<\/td><\/tr><tr><td>T_CLK<\/td><td>GPIO 25<\/td><\/tr><tr><td>SDO(MISO)<\/td><td>GPIO 12<\/td><\/tr><tr><td>LED<\/td><td>GPIO 21<\/td><\/tr><tr><td>SCK<\/td><td>GPIO 14<\/td><\/tr><tr><td>SDI(MOSI)<\/td><td>GPIO 13<\/td><\/tr><tr><td>D\/C<\/td><td>GPIO 2<\/td><\/tr><tr><td>RESET<\/td><td>EN\/RESET<\/td><\/tr><tr><td>CS<\/td><td>GPIO 15<\/td><\/tr><tr><td>GND<\/td><td>GND<\/td><\/tr><tr><td>VCC<\/td><td>5V (or 3.3V)*<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>* In the VCC pin, you can either use 5V or 3.3V depending if your <strong>J1<\/strong> connection is open or closed (by default it&#8217;s usually open as you can see in the figure below).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>VCC = 5V | J1=OPEN\nVCC = 3.3V | J1=CLOSE<\/code><\/pre>\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\/2024\/03\/TFT-LCD-touchscreen-J1-connection.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"TFT LCD Touchscreen display J1 connection\" class=\"wp-image-150009\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/TFT-LCD-touchscreen-J1-connection.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/TFT-LCD-touchscreen-J1-connection.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\">5) 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\" 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 with the 2.8 inch ILI9341 240\u00d7320 TFT LCD Touchscreen using Arduino IDE.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/lvgl-esp32-tft-touchscreen-display-ili9341-arduino\/\" title=\"\"><strong>LVGL with ESP32 TFT LCD Touchscreen Display \u2013 2.8 inch ILI9341 240\u00d7320 (Arduino IDE)<\/strong><\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">6) 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. In the Arduino IDE, go to <strong>Sketch <\/strong>&gt; <strong>Include Library<\/strong> &gt; <strong>Manage Libraries<\/strong>. Search for<strong> Adafruit BME280<\/strong> Library on 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<h3 class=\"wp-block-heading rntbox rntclgreen\">7) Wiring the BME280 Sensor and LDR to the ESP32<\/h3>\n\n\n\n<p>We\u2019ll use I2C communication protocol to get data from the BME280 sensor. Wire the BME280 to the ESP32 according to the following table.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>BME280<\/strong><\/td><td><strong>ESP32<\/strong><\/td><\/tr><tr><td>VIN<\/td><td>3V3<\/td><\/tr><tr><td>GND<\/td><td>GND<\/td><\/tr><tr><td>SCL<\/td><td>GPIO 22<\/td><\/tr><tr><td>SDA<\/td><td>GPIO 27<\/td><\/tr><\/tbody><\/table><\/figure>\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\/2024\/12\/ESP32-TFT-LVGL-Display-Temperature-Line-Chart-BME280.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 TFT LVGL Display Temperature Line Chart BME280\" class=\"wp-image-164498\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/ESP32-TFT-LVGL-Display-Temperature-Line-Chart-BME280.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/ESP32-TFT-LVGL-Display-Temperature-Line-Chart-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<h2 class=\"wp-block-heading\">ESP32 TFT: Displaying Temperature Line Chart &#8211; Arduino Code<\/h2>\n\n\n\n<p>The following code will create the chart with values from the BME280 sensor.<\/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-lvgl-line-chart\/  |  https:\/\/RandomNerdTutorials.com\/esp32-tft-lvgl-line-chart\/\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\/\/ Install Adafruit Unified Sensor and Adafruit BME280 Library\n#include &lt;Wire.h&gt;\n#include &lt;Adafruit_Sensor.h&gt;\n#include &lt;Adafruit_BME280.h&gt;\n#define I2C_SDA 27\n#define I2C_SCL 22\nTwoWire I2CBME = TwoWire(0);\nAdafruit_BME280 bme;\n\n\/\/ SET VARIABLE TO 0 FOR TEMPERATURE IN FAHRENHEIT DEGREES\n#define TEMP_CELSIUS 1\n#define BME_NUM_READINGS 20\nfloat bme_last_readings[BME_NUM_READINGS] = {-20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0};\nfloat scale_min_temp;\nfloat scale_max_temp;\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\/\/ 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\/\/ Generally, you should use &quot;unsigned long&quot; for variables that hold time\nunsigned long previousMillis = 0; \/\/ will store last time the chart was updated\n\/\/ Interval at which the chart will be updated (milliseconds) 10000 milliseconds = 10 seconds\nconst long interval = 10000;\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\n\/\/ Draw a label on that chart with the value of the pressed point\nstatic void chart_draw_label_cb(lv_event_t * e) {\n  lv_event_code_t code = lv_event_get_code(e);\n  lv_obj_t * chart = (lv_obj_t*) lv_event_get_target(e);\n\n  if(code == LV_EVENT_VALUE_CHANGED) {\n    lv_obj_invalidate(chart);\n  }\n  if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {\n    int32_t * s = (int32_t*)lv_event_get_param(e);\n    *s = LV_MAX(*s, 20);\n  }\n  \/\/ Draw the label on the chart based on the pressed point\n  else if(code == LV_EVENT_DRAW_POST_END) {\n    int32_t id = lv_chart_get_pressed_point(chart);\n    if(id == LV_CHART_POINT_NONE) return;\n\n    LV_LOG_USER(&quot;Selected point %d&quot;, (int)id);\n\n    lv_chart_series_t * ser = lv_chart_get_series_next(chart, NULL);\n    while(ser) {\n      lv_point_t p;\n      lv_chart_get_point_pos_by_id(chart, ser, id, &amp;p);\n\n      int32_t * y_array = lv_chart_get_y_array(chart, ser);\n      int32_t value = y_array[id];\n      char buf[16];\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      \/\/ Preparing the label text for the selected data point\n      lv_snprintf(buf, sizeof(buf), LV_SYMBOL_DUMMY &quot; %3.2f %s &quot;, float(bme_last_readings[id]), degree_symbol);\n\n      \/\/ Draw the rectangular label that will display the temperature value\n      lv_draw_rect_dsc_t draw_rect_dsc;\n      lv_draw_rect_dsc_init(&amp;draw_rect_dsc);\n      draw_rect_dsc.bg_color = lv_color_black();\n      draw_rect_dsc.bg_opa = LV_OPA_60;\n      draw_rect_dsc.radius = 2;\n      draw_rect_dsc.bg_image_src = buf;\n      draw_rect_dsc.bg_image_recolor = lv_color_white();\n      \/\/ Rectangular label size\n      lv_area_t a;\n      a.x1 = chart-&gt;coords.x1 + p.x - 35;\n      a.x2 = chart-&gt;coords.x1 + p.x + 35;\n      a.y1 = chart-&gt;coords.y1 + p.y - 30;\n      a.y2 = chart-&gt;coords.y1 + p.y - 10;\n      lv_layer_t * layer = lv_event_get_layer(e);\n      lv_draw_rect(layer, &amp;draw_rect_dsc, &amp;a);\n      ser = lv_chart_get_series_next(chart, ser);\n    }\n  }\n  else if(code == LV_EVENT_RELEASED) {\n    lv_obj_invalidate(chart);\n  }\n}\n\n\/\/ Draw chart\nvoid lv_draw_chart(void) {\n  \/\/ Clear screen\n  lv_obj_clean(lv_scr_act());\n\n  \/\/ Create a a text label aligned on top\n  lv_obj_t * label = lv_label_create(lv_screen_active());\n  lv_label_set_text(label, &quot;BME280 Temperature Readings&quot;);\n  lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 10);\n\n  \/\/ Create a container to display the chart and scale\n  lv_obj_t * container_row = lv_obj_create(lv_screen_active());\n  lv_obj_set_size(container_row, SCREEN_HEIGHT-20,  SCREEN_WIDTH-40);\n  lv_obj_align(container_row, LV_ALIGN_BOTTOM_MID, 0, -10);\n  \/\/ Set the container in a flexbox row layout aligned center\n  lv_obj_set_flex_flow(container_row, LV_FLEX_FLOW_ROW);\n  lv_obj_set_flex_align(container_row, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);\n\n  \/\/ Create a chart\n  lv_obj_t * chart = lv_chart_create(container_row);\n  lv_obj_set_size(chart, SCREEN_HEIGHT-90, SCREEN_WIDTH-70);\n  lv_chart_set_point_count(chart, BME_NUM_READINGS);\n  lv_obj_add_event_cb(chart, chart_draw_label_cb, LV_EVENT_ALL, NULL);\n  lv_obj_refresh_ext_draw_size(chart);\n\n  \/\/ Add a data series\n  lv_chart_series_t * chart_series = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_GREEN), LV_CHART_AXIS_PRIMARY_Y);\n\n  for(int i = 0; i &lt; BME_NUM_READINGS; i++) {\n    if(float(bme_last_readings[i]) != -20.0) { \/\/ Ignores default array values\n      \/\/ Set points in the chart and scale them with an *100 multiplier to remove the 2 floating-point numbers\n      chart_series-&gt;y_points[i] = float(bme_last_readings[i]) * 100;\n    }\n  }\n  \/\/ Set the chart range and also scale it with an *100 multiplier to remove the 2 floating-point numbers\n  lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, int(scale_min_temp-1)*100, int(scale_max_temp+1)*100);\n  lv_chart_refresh(chart); \/\/ Required to update the chart with the new values\n\n  \/\/ Create a scale (y axis for the temperature) aligned vertically on the right\n  lv_obj_t * scale = lv_scale_create(container_row);\n  lv_obj_set_size(scale, 15, SCREEN_WIDTH-90);\n  lv_scale_set_mode(scale, LV_SCALE_MODE_VERTICAL_RIGHT);\n  lv_scale_set_label_show(scale, true);\n  \/\/ Set the scale ticks count \n  lv_scale_set_total_tick_count(scale, int(scale_max_temp+2) - int(scale_min_temp-1));\n  if((int(scale_max_temp+2) - int(scale_min_temp-1)) &lt; 10) {\n    lv_scale_set_major_tick_every(scale, 1); \/\/ set y axis to have 1 tick every 1 degree\n  }\n  else {\n    lv_scale_set_major_tick_every(scale, 10); \/\/ set y axis to have 1 tick every 10 degrees\n  }\n  \/\/ Set the scale style and range\n  lv_obj_set_style_length(scale, 5, LV_PART_ITEMS);\n  lv_obj_set_style_length(scale, 10, LV_PART_INDICATOR);\n  lv_scale_set_range(scale, int(scale_min_temp-1), int(scale_max_temp+1));\n}\n\n\/\/ Get the latest BME readings\nvoid get_bme_readings(void) {\n  #if TEMP_CELSIUS\n    float bme_temp = bme.readTemperature();\n  #else\n    float bme_temp = 1.8 * bme.readTemperature() + 32;  \n  #endif\n  \n  \/\/ Reset scale range (chart y axis) variables\n  scale_min_temp = 120.0;\n  scale_max_temp = -20.0;\n\n  \/\/ Shift values to the left of the array and inserts the latest reading at the end\n  for (int i = 0; i &lt; BME_NUM_READINGS; i++) {\n    if(i == (BME_NUM_READINGS-1) &amp;&amp; float(bme_temp) &lt; 120.0) {\n      bme_last_readings[i] = float(bme_temp);  \/\/ Inserts the new reading at the end\n    }\n    else {\n      bme_last_readings[i] = float(bme_last_readings[i + 1]);  \/\/ Shift values to the left of the array\n    }\n    \/\/ Get the min\/max value in the array to set the scale range (chart y axis)\n    if((float(bme_last_readings[i]) &lt; scale_min_temp) &amp;&amp; (float(bme_last_readings[i]) != -20.0 )) {\n      scale_min_temp = bme_last_readings[i];\n    }\n    if((float(bme_last_readings[i]) &gt; scale_max_temp) &amp;&amp; (float(bme_last_readings[i]) != -20.0 )) {\n      scale_max_temp = bme_last_readings[i];\n    }\n  }\n  Serial.print(&quot;Min temp: &quot;);\n  Serial.println(float(scale_min_temp));\n  Serial.print(&quot;Max temp: &quot;);\n  Serial.println(float(scale_max_temp));\n  Serial.print(&quot;BME last reading: &quot;);\n  Serial.println(float(bme_last_readings[BME_NUM_READINGS-1]));\n  lv_draw_chart();\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  I2CBME.begin(I2C_SDA, I2C_SCL, 100000);\n  bool status;\n  \/\/ Passing a &amp;Wire2 to set custom I2C ports\n  status = bme.begin(0x76, &amp;I2CBME);\n  if (!status) {\n    Serial.println(&quot;Could not find a valid BME280 sensor, check wiring!&quot;);\n    while (1);\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  get_bme_readings();\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  unsigned long currentMillis = millis();\n  if (currentMillis - previousMillis &gt;= interval) {\n    \/\/ save the last time that chart was updated\n    previousMillis = currentMillis;\n    get_bme_readings();    \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_LVGL_Line_Chart_BME280\/ESP32_LVGL_Line_Chart_BME280.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How Does the Code Work?<\/h2>\n\n\n\n<p>Let\u2019s take a look at how to get temperature from the BME280 sensor and add the current reading to the line chart. Alternatively, you can skip to the <a href=\"#demonstration\" title=\"\">Demonstration <\/a>section.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Including Libraries<\/h3>\n\n\n\n<p>In all your 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>You need to include the following libraries to interface with the BME280 sensor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include &lt;Wire.h&gt;\n#include &lt;Adafruit_Sensor.h&gt;\n#include &lt;Adafruit_BME280.h&gt;<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">BME280 I2C Pins<\/h3>\n\n\n\n<p>Set the I2C pins to use the BME280 sensor, create a new I2C bus instance to use those pins, and create an <span class=\"rnthl rntliteral\">Adafruit_BME280<\/span> object called <span class=\"rnthl rntliteral\">bme<\/span> to refer to the sensor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define I2C_SDA 27\n#define I2C_SCL 22\nTwoWire I2CBME = TwoWire(0);\nAdafruit_BME280 bme;<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Celsius or Fahrenheit<\/h3>\n\n\n\n<p>Our code is prepared to display the temperature in Celsius or Fahrenheit degrees. To choose your desired unit, you can set the value of the <span class=\"rnthl rntliteral\">TEMP_CELSIUS<\/span> variable. It is set to <span class=\"rnthl rntliteral\">1<\/span> by default to display the temperature in Celsius degrees.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define TEMP_CELSIUS 1 &nbsp; &nbsp;<\/code><\/pre>\n\n\n\n<p>If you want to display in Fahrenheit degrees instead, set it to <span class=\"rnthl rntliteral\">0<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define TEMP_CELSIUS 0<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Number of Readings and Scale Variables<\/h3>\n\n\n\n<p>The data to be displayed on the chart needs to be placed in an array. We\u2019ll display a maximum of 20 readings. These are saved on the <span class=\"rnthl rntliteral\">bme_last_readings<\/span> array.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define BME_NUM_READINGS 20\nfloat bme_last_readings&#091;BME_NUM_READINGS] = {-20.0, -20.0, -20.0, -20.0, -20.0,\n-20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0, -20.0,\n-20.0, -20.0, -20.0, -20.0};<\/code><\/pre>\n\n\n\n<p>We also create two global variables <span class=\"rnthl rntliteral\">scale_min_temp<\/span> and <span class=\"rnthl rntliteral\">scale_max_temp<\/span> that will be used to adjust the scale range.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>float scale_min_temp;\nfloat scale_max_temp;<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Defining the Display Width and Height<\/h3>\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 241\n#define SCREEN_HEIGHT 320<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Creating a Drawing Buffer<\/h3>\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<p>You should also include this in all LVGL examples.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Debugging Function<\/h3>\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<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\">Initializing the BME280 sensor<\/h4>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">setup()<\/span>, start by initializing the BME280 sensor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>I2CBME.begin(I2C_SDA, I2C_SCL, 100000);\nbool status;\n\/\/ Passing a &amp;Wire2 to set custom I2C ports\nstatus = bme.begin(0x76, &amp;I2CBME);\nif (!status) {\n  Serial.println(\"Could not find a valid BME280 sensor, check wiring!\");\n  while (1);\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<h3 class=\"wp-block-heading\">Getting BME280 Readings<\/h3>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">setup()<\/span>, we call the <span class=\"rnthl rntliteral\">get_bme_readings()<\/span> which will get new sensor readings and display them on the chart.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>get_bme_readings();<\/code><\/pre>\n\n\n\n<p>This function is also called every 10 seconds (<span class=\"rnthl rntliteral\">interval<\/span> variable) in the <span class=\"rnthl rntliteral\">loop()<\/span> to add a new data point to the chart.<\/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 that chart was updated\n  previousMillis = currentMillis;\n  get_bme_readings();\n}<\/code><\/pre>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">get_bme_readings()<\/span>, we start by getting a new temperature reading and save it on the <span class=\"rnthl rntliteral\">bme_temp<\/span> variable (in Celsius or Fahrenheit degrees).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#if TEMP_CELSIUS\n  float bme_temp = bme.readTemperature();\n#else\n  float bme_temp = 1.8 * bme.readTemperature() + 32;\n#endif<\/code><\/pre>\n\n\n\n<p>Every time we get a new data point, we\u2019ll reset the scale range (y-axis).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Reset scale range (chart y axis) variables\nscale_min_temp = 120.0;\nscale_max_temp = -20.0;<\/code><\/pre>\n\n\n\n<p>We add the new temperature value at the end of the array and shift all data points to the left of the array.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Shift values to the left of the array and inserts the latest reading at the end\nfor (int i = 0; i &lt; BME_NUM_READINGS; i++) {\n  if(i == (BME_NUM_READINGS-1) &amp;&amp; float(bme_temp) &lt; 120.0) {\n    bme_last_readings&#091;i] = float(bme_temp); \/\/Inserts the new reading at the end\n  }\n  else {\n    bme_last_readings&#091;i] = float(bme_last_readings&#091;i+1]);\n    \/\/ Shift values to the left of the array\n  }<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">bme_last_readings<\/span> array now contains the data to be displayed on the chart.<\/p>\n\n\n\n<p>We\u2019ll go through the array and get the maximum and the minimum temperature readings and save them on the <span class=\"rnthl rntliteral\">scale_max_temp<\/span> and <span class=\"rnthl rntliteral\">scale_min_temp<\/span> variables so that we can adjust the y-axis later.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Get the min\/max value in the array to set the scale range (chart y axis)\nif((float(bme_last_readings&#091;i]) &lt; scale_min_temp) &amp;&amp; (float(bme_last_readings&#091;i]) != -20.0 )) {\n  scale_min_temp = bme_last_readings&#091;i];\n}\nif((float(bme_last_readings&#091;i]) &gt; scale_max_temp) &amp;&amp; (float(bme_last_readings&#091;i]) != -20.0 )) {\n  scale_max_temp = bme_last_readings&#091;i];\n}<\/code><\/pre>\n\n\n\n<p>Now that we have our array ready and the maximum and minimum temperature values, we can start drawing the chart. We created a function called <span class=\"rnthl rntliteral\">lv_draw_chart()<\/span> where we added all the instructions<br>to draw the chart.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>lv_draw_chart();<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Drawing the Chart<\/h3>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">lv_draw_chart()<\/span> we draw the chart and add all the other widgets to the screen.<\/p>\n\n\n\n<p>We add a text label at the top with the <span class=\"rnthl rntliteral\">BME280 Temperature Readings<\/span> text.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Create a a text label aligned on top\nlv_obj_t * label = lv_label_create(lv_screen_active());\nlv_label_set_text(label, \"BME280 Temperature Readings\");\nlv_obj_align(label, LV_ALIGN_TOP_MID, 0, 10);<\/code><\/pre>\n\n\n\n<p>Next, we create a container (<span class=\"rnthl rntliteral\">container_row<\/span>) where we\u2019ll add the chart and the corresponding scale (y-axis) and we set its alignment.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Create a container to display the chart and scale\nlv_obj_t * container_row = lv_obj_create(lv_screen_active());\nlv_obj_set_size(container_row, SCREEN_HEIGHT-20, SCREEN_WIDTH-40);\nlv_obj_align(container_row, LV_ALIGN_BOTTOM_MID, 0, -10);\n\/\/ Set the container in a flexbox row layout aligned center\nlv_obj_set_flex_flow(container_row, LV_FLEX_FLOW_ROW);\nlv_obj_set_flex_align(container_row, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);<\/code><\/pre>\n\n\n\n<p>We create an LVGL chart object using the <span class=\"rnthl rntliteral\">lv_chart_create()<\/span> function. We pass as argument where we want to place the chart. In this case, we want to place it inside the <span class=\"rnthl rntliteral\">container_row<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>lv_obj_t * chart = lv_chart_create(container_row);<\/code><\/pre>\n\n\n\n<p>Set the chart size.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>lv_obj_set_size(chart, SCREEN_HEIGHT-90, SCREEN_WIDTH-70);<\/code><\/pre>\n\n\n\n<p>Set the number of points you want to display simultaneously on the chart.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>lv_chart_set_point_count(chart, BME_NUM_READINGS);<\/code><\/pre>\n\n\n\n<p>Add an event to the chart so that it displays the pressed point value\u2014that will be handled inside the <span class=\"rnthl rntliteral\">chart_draw_label_cb()<\/span> callback function.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>lv_obj_add_event_cb(chart, chart_draw_label_cb, LV_EVENT_ALL, NULL);<\/code><\/pre>\n\n\n\n<p>After creating the chart, we need to create a data series for the chart using the <span class=\"rnthl rntliteral\">lv_chart_add_series()<\/span>. Pass as argument the chart you\u2019re referring to, the color of the series, and the Y axis.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>lv_chart_series_t * chart_series = lv_chart_add_series(chart,\nlv_palette_main(LV_PALETTE_GREEN), LV_CHART_AXIS_PRIMARY_Y);<\/code><\/pre>\n\n\n\n<p>Afterward, we add all our points in the array to the chart series.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>for(int i = 0; i &lt; BME_NUM_READINGS; i++) {\n  if(float(bme_last_readings&#091;i]) != -20.0) { \/\/ Ignores default array values\n    \/\/ Set points in the chart and scale them with an\n    \/\/ *100 multiplier to remove the 2 floating-point numbers\n   chart_series-&gt;y_points&#091;i] = float(bme_last_readings&#091;i]) * 100;\n  }\n}<\/code><\/pre>\n\n\n\n<p>Set the chart range taking into account the <span class=\"rnthl rntliteral\">scale_max_temp<\/span> and <span class=\"rnthl rntliteral\">scale_min_temp<\/span> values that we got previously.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Set the chart range and also scale it with an\n\/\/ *100 multiplier to remove the 2 floating-point numbers\nlv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, int(scale_min_temp-1)*100,\nint(scale_max_temp+1)*100);<\/code><\/pre>\n\n\n\n<p>Call the <span class=\"rnthl rntliteral\">lv_chart_refresh()<\/span> function to update all values on the chart.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>lv_chart_refresh(chart); \/\/ Required to update the chart with the new values<\/code><\/pre>\n\n\n\n<p>Create a vertical scale for the chart using the <span class=\"rnthl rntliteral\">lv_scale_create()<\/span> function and place it inside the <span class=\"rnthl rntliteral\">container_row<\/span> aligned vertically on the right.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Create a scale (y axis for the temperature) aligned vertically on the right\nlv_obj_t * scale = lv_scale_create(container_row);\nlv_obj_set_size(scale, 15, SCREEN_WIDTH-90);\nlv_scale_set_mode(scale, LV_SCALE_MODE_VERTICAL_RIGHT);\nlv_scale_set_label_show(scale, true);<\/code><\/pre>\n\n\n\n<p>Set the scale smaller divisions.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Set the scale ticks count\nlv_scale_set_total_tick_count(scale,int(scale_max_temp+2)-int(scale_min_temp-1));\nif((int(scale_max_temp+2) - int(scale_min_temp-1)) &lt; 10) {\n  lv_scale_set_major_tick_every(scale, 1); \/\/ set y axis to have 1 tick every 1 degree\n}\nelse {\n  lv_scale_set_major_tick_every(scale, 10);\/\/set y axis to have 1 tick every 10 degrees\n}<\/code><\/pre>\n\n\n\n<p>Set the scale style and range.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Set the scale style and range\nlv_obj_set_style_length(scale, 5, LV_PART_ITEMS);\nlv_obj_set_style_length(scale, 10, LV_PART_INDICATOR);\nlv_scale_set_range(scale, int(scale_min_temp-1), int(scale_max_temp+1));<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Drawing the Chart<\/h3>\n\n\n\n<p>When you press the chart, it will display a label with the values for the pressed data point.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>lv_obj_add_event_cb(chart, chart_draw_label_cb, LV_EVENT_ALL, NULL);<\/code><\/pre>\n\n\n\n<p>All of that is handled on the <span class=\"rnthl rntliteral\">chart_draw_label_cb()<\/span> function.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Draw a label on that chart with the value of the pressed point\nstatic void chart_draw_label_cb(lv_event_t * e) {\n  lv_event_code_t code = lv_event_get_code(e);\n  lv_obj_t * chart = (lv_obj_t*) lv_event_get_target(e);\n  if(code == LV_EVENT_VALUE_CHANGED) {\n    lv_obj_invalidate(chart);\n  }\n  if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {\n    int32_t * s = (int32_t*)lv_event_get_param(e);\n    *s = LV_MAX(*s, 20);\n  }\n  \/\/ Draw the label on the chart based on the pressed point\n  else if(code == LV_EVENT_DRAW_POST_END) {\n    int32_t id = lv_chart_get_pressed_point(chart);\n    if(id == LV_CHART_POINT_NONE) return;\n      LV_LOG_USER(\"Selected point %d\", (int)id);\n      lv_chart_series_t * ser = lv_chart_get_series_next(chart, NULL);\n      while(ser) {\n        lv_point_t p;\n        lv_chart_get_point_pos_by_id(chart, ser, id, &amp;p);\n        int32_t * y_array = lv_chart_get_y_array(chart, ser);\n        int32_t value = y_array&#091;id];\n        char buf&#091;16];\n        #if TEMP_CELSIUS\n          const char degree_symbol&#091;] = \"\\u00B0C\";\n        #else\n          const char degree_symbol&#091;] = \"\\u00B0F\";\n        #endif\n        \/\/ Preparing the label text for the selected data point\n        lv_snprintf(buf, sizeof(buf), LV_SYMBOL_DUMMY \" %3.2f %s \", float(bme_last_readings&#091;id]), degree_symbol);\n        \/\/ Draw the rectangular label that will display the temperature value\n        lv_draw_rect_dsc_t draw_rect_dsc;\n        lv_draw_rect_dsc_init(&amp;draw_rect_dsc);\n        draw_rect_dsc.bg_color = lv_color_black();\n        draw_rect_dsc.bg_opa = LV_OPA_60;\n        draw_rect_dsc.radius = 2;\n        draw_rect_dsc.bg_image_src = buf;\n        draw_rect_dsc.bg_image_recolor = lv_color_white();\n        \/\/ Rectangular label size\n        lv_area_t a;\n        a.x1 = chart-&gt;coords.x1 + p.x - 35;\n        a.x2 = chart-&gt;coords.x1 + p.x + 35;\n        a.y1 = chart-&gt;coords.y1 + p.y - 30;\n        a.y2 = chart-&gt;coords.y1 + p.y - 10;\n        lv_layer_t * layer = lv_event_get_layer(e);\n        lv_draw_rect(layer, &amp;draw_rect_dsc, &amp;a);\n        ser = lv_chart_get_series_next(chart, ser);\n      }\n    }\n    else if(code == LV_EVENT_RELEASED) {\n      lv_obj_invalidate(chart);\n    }\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"demonstration\">Demonstration<\/h2>\n\n\n\n<p>Upload the code to your board. Go to <strong>Tools <\/strong>&gt; <strong>Board <\/strong>and select <strong>ESP32 <\/strong>&gt; <strong>ESP32 Dev Module<\/strong>. Then, select the right COM port in <strong>Tools <\/strong>&gt; <strong>Port<\/strong>. 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 uploading the code, it will display the chart with one point. Wait 10 seconds to get a second point, 10 seconds more for the third point, and so on.<\/p>\n\n\n\n<p>Wait until you have the chart filled with the 20 data points. A new value is added every 10 seconds\u2014the chart is automatically updated.<\/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\/2024\/12\/ESP32-TFT-LVGL-Display-Temperature-Line-Chart-BME280-Demonstration.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 TFT LVGL Display Temperature Line Chart BME280 Demonstration\" class=\"wp-image-164497\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/ESP32-TFT-LVGL-Display-Temperature-Line-Chart-BME280-Demonstration.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/ESP32-TFT-LVGL-Display-Temperature-Line-Chart-BME280-Demonstration.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>You can press on a specific data point to check its precise value.<\/p>\n\n\n\n<p>The serial monitor displays the latest temperature reading as well as the minimum and maximum values from the array.<\/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=\"695\" height=\"371\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/ESP32-CYD-BME280-line-chart-serial-monitor-temperature-demonstration.png?resize=695%2C371&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 CYD BME280 line chart serial monitor temperature demonstration\" class=\"wp-image-164494\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/ESP32-CYD-BME280-line-chart-serial-monitor-temperature-demonstration.png?w=695&amp;quality=100&amp;strip=all&amp;ssl=1 695w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/ESP32-CYD-BME280-line-chart-serial-monitor-temperature-demonstration.png?resize=300%2C160&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 695px) 100vw, 695px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>In this tutorial, you learned to display sensor data on a line chart with an ESP32 and a TFT display using the LVGL library.<\/p>\n\n\n\n<p>We hope you found this tutorial useful. We&#8217;re preparing more guides about this board, so stay tuned. 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\/esp32-tft-lvgl-display-bme280-data-table\/\">ESP32 TFT with LVGL: Display BME280 Sensor Data on a Table<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-lvgl-ds18b20-tempreature-tft-display\/\">ESP32 with LVGL: Display DS18B20 Sensor Readings on TFT LCD (Text and Arc)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-tft-display-image-lvgl-arduino\/\">ESP32 with TFT: Display Image using LVGL \u2013 2.8 inch ILI9341 240\u00d7320 (Arduino)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-tft-lvgl-weather-station\/\">ESP32 TFT with LVGL: Weather Station (Description, Temperature, Humidity)<\/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><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this guide, you&#8217;ll learn how to display temperature from the BME280 sensor on an ESP32 and a TFT display using LVGL (Light Versatile Graphics Library). You\u2019ll learn how to &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP32 TFT with LVGL: Display Temperature on Line Chart (BME280)\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp32-tft-lvgl-line-chart\/#more-165008\" aria-label=\"Read more about ESP32 TFT with LVGL: Display Temperature on Line Chart (BME280)\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":1,"featured_media":165010,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[281,276,277,299,264],"tags":[],"class_list":["post-165008","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp32-project","category-esp32","category-esp32-arduino-ide","category-0-esp32","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/12\/ESP32-TFT-Display-BME280-Line-Chart.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\/165008","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\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=165008"}],"version-history":[{"count":2,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/165008\/revisions"}],"predecessor-version":[{"id":167653,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/165008\/revisions\/167653"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/165010"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=165008"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=165008"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=165008"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}