{"id":107720,"date":"2021-11-11T14:41:59","date_gmt":"2021-11-11T14:41:59","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=107720"},"modified":"2021-11-11T15:17:40","modified_gmt":"2021-11-11T15:17:40","slug":"esp32-ble-server-client","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp32-ble-server-client\/","title":{"rendered":"ESP32 BLE Server and Client (Bluetooth Low Energy)"},"content":{"rendered":"\n<p>Learn how to make a BLE (Bluetooth Low Energy) connection between two ESP32 boards. One ESP32 is going to be the server, and the other ESP32 will be the client. The BLE server advertises characteristics that contain sensor readings that the client can read. The ESP32 BLE client reads the values of those characteristics (temperature and humidity) and displays them on an OLED display.<\/p>\n\n\n\n<div class=\"wp-block-image\"><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\/2021\/11\/ESP32-BLE-Client-Server.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 BLE Server and Client BLuetooth Low Energy Arduino IDE\" class=\"wp-image-107770\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Client-Server.jpg?w=1280&amp;quality=100&amp;strip=all&amp;ssl=1 1280w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Client-Server.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Client-Server.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Client-Server.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n\n<p class=\"rntbox rntclblue\"><strong>Recommended Reading:<\/strong> <a href=\"https:\/\/randomnerdtutorials.com\/esp32-bluetooth-low-energy-ble-arduino-ide\/\">Getting Started with ESP32 Bluetooth Low Energy (BLE)<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is Bluetooth Low Energy?<\/h2>\n\n\n\n<p>Before going straight to the project, it is important to take a quick look at some essential BLE concepts so that you&#8217;re able to better understand the project later on. If you&#8217;re already familiar with BLE, you can skip to the <a href=\"#project-overview\">Project Overview<\/a> section.<\/p>\n\n\n\n<p>Bluetooth Low Energy, BLE for short, is a power-conserving variant of Bluetooth. BLE\u2019s primary application is short-distance transmission of small amounts of data (low bandwidth). Unlike Bluetooth that is always on, BLE remains in sleep mode constantly except for when a connection is initiated.<\/p>\n\n\n\n<p>This makes it consume very low power. BLE consumes approximately 100x less power than Bluetooth (depending on the use case). You can <a href=\"https:\/\/www.bluetooth.com\/learn-about-bluetooth\/tech-overview\/\" target=\"_blank\" rel=\"noreferrer noopener\" title=\"#https:\/\/www.bluetooth.com\/learn-about-bluetooth\/tech-overview\/\">check the main differences between Bluetooth and Bluetooth Low Energy here<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">BLE Server and Client<\/h3>\n\n\n\n<p>With Bluetooth Low Energy, there are two types of devices: the server and the client. The ESP32 can act either as a client or as a server.<\/p>\n\n\n\n<p>The server advertises its existence, so it can be found by other devices and contains data that the client can read. The client scans the nearby devices, and when it finds the server it is looking for, it establishes a connection and listens for incoming data. This is called point-to-point communication.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"750\" height=\"308\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/BLE-Server-Client-Server-Advertising-03.png?resize=750%2C308&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"BLE Client Server Server Advertising\" class=\"wp-image-107774\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/BLE-Server-Client-Server-Advertising-03.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/BLE-Server-Client-Server-Advertising-03.png?resize=300%2C123&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n\n<p>There are other possible communication modes like broadcast mode and mesh network (not covered in this tutorial).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">GATT<\/h3>\n\n\n\n<p>GATT stands for Generic Attributes and it defines a hierarchical data structure that is exposed to connected BLE devices. This means that GATT defines the way that two BLE devices send and receive standard messages.\u00a0Understanding this hierarchy is important because it will make it easier to understand how to use BLE with the ESP32.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"750\" height=\"423\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/GATT-ESP32-BLE-Server-Client-Example.png?resize=750%2C423&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"GATT Hierarchy ESP32 BLE Server Client Example\" class=\"wp-image-107772\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/GATT-ESP32-BLE-Server-Client-Example.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/GATT-ESP32-BLE-Server-Client-Example.png?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Profile<\/strong>: standard collection of services for a specific use case;<\/li><li><strong>Service<\/strong>: collection of related information, like sensor readings, battery level, heart rate, etc. ;<\/li><li><strong>Characteristic<\/strong>: it is where the actual data is saved on the hierarchy (<strong>value<\/strong>);<\/li><li><strong>Descriptor<\/strong>: metadata about the data;<\/li><li><strong>Properties<\/strong>: describe how the characteristic value can be interacted with. For example: read, write, notify, broadcast, indicate, etc.<\/li><\/ul>\n\n\n\n<p>In our example, we&#8217;ll create a service with two <em>characteristics<\/em>. One for the temperature and another for the humidity. The actual temperature and humidity readings are saved on the <em>value <\/em>under their <em>characteristics<\/em>. Each characteristic has the <em>notify <\/em>property, so that it notifies the client whenever the values change.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">UUID<\/h3>\n\n\n\n<p>Each service, characteristic, and descriptor have a UUID (Universally Unique Identifier). A UUID is a unique 128-bit (16 bytes) number. For example:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><strong>55072829-bc9e-4c53-938a-74a6d4c78776<\/strong><\/pre>\n\n\n\n<p>There are shortened UUIDs for all types, services, and profiles specified in the <a href=\"https:\/\/www.bluetooth.com\/specifications\/gatt\/services\" target=\"_blank\" rel=\"noreferrer noopener\">SIG (Bluetooth Special Interest Group)<\/a>.<\/p>\n\n\n\n<p>But if your application needs its own UUID, you can generate it using this <a href=\"https:\/\/www.uuidgenerator.net\/\" target=\"_blank\" rel=\"noreferrer noopener\">UUID generator website<\/a>.<\/p>\n\n\n\n<p>In summary, the UUID is used for uniquely identifying information. For example, it can identify a particular service provided by a Bluetooth device.<\/p>\n\n\n\n<p>For a more detailed introduction about BLE, read our getting started guide:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-bluetooth-low-energy-ble-arduino-ide\/\">Getting Started with ESP32 Bluetooth Low Energy (BLE) on Arduino IDE<\/a><\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"project-overview\">Project Overview<\/h2>\n\n\n\n<p>In this tutorial, you\u2019re going to learn how to make a BLE connection between two ESP32 boards. One ESP32 is going to be the BLE server, and the other ESP32 will be the BLE client. <\/p>\n\n\n\n<div class=\"wp-block-image\"><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\/2021\/11\/ESP32-BLE-Server-nRF-Connect-App-f.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 BLE Client Server OLED Display Demonstration\" class=\"wp-image-107790\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Server-nRF-Connect-App-f.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Server-nRF-Connect-App-f.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\n<p>The ESP32 BLE server is connected to a <a href=\"https:\/\/randomnerdtutorials.com\/esp32-bme280-arduino-ide-pressure-temperature-humidity\/\">BME280 sensor<\/a> and it updates its temperature and humidity characteristic values every 30 seconds. <\/p>\n\n\n\n<p>The ESP32 client connects to the BLE server and it is notified of its temperature and humidity characteristic values. This ESP32 is connected to an OLED display and it prints the latest readings. <\/p>\n\n\n\n<p>This project is divided into two parts:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"#ESP32-BLE-Server\"><strong>Part 1<\/strong>\u00a0\u2013 ESP32 BLE server<\/a><\/li><li><a href=\"#ESP32-BLE-Client\" title=\"#ESP32-BLE-Client\"><strong>Part 2<\/strong>\u00a0\u2013 ESP32 BLE client<\/a><\/li><\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Parts Required<\/h3>\n\n\n\n<p>Here&#8217;s a list of the parts required to follow this project:<\/p>\n\n\n\n<p><strong>ESP32 BLE Server:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/makeradvisor.com\/tools\/esp32-dev-board-wi-fi-bluetooth\/\" target=\"_blank\" rel=\"noreferrer noopener\">ESP32 DOIT DEVKIT V1 Board<\/a> (read\u00a0<a href=\"https:\/\/makeradvisor.com\/esp32-development-boards-review-comparison\/\" target=\"_blank\" rel=\"noreferrer noopener\">Best ESP32 development boards<\/a>)<\/li><li><a href=\"https:\/\/makeradvisor.com\/tools\/bme280-sensor-module\/\" target=\"_blank\" rel=\"noreferrer noopener\">BME280 Sensor<\/a><\/li><li><a href=\"https:\/\/makeradvisor.com\/tools\/jumper-wires-kit-120-pieces\/\" target=\"_blank\" rel=\"noreferrer noopener\">Jumper wires<\/a><\/li><li><a href=\"https:\/\/makeradvisor.com\/tools\/mb-102-solderless-breadboard-830-points\/\" target=\"_blank\" rel=\"noreferrer noopener\">Breadboard<\/a><\/li><li>Smartphone with Bluetooth (optional)<\/li><\/ul>\n\n\n\n<p> <strong>ESP32 BLE Client:<\/strong> <\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/makeradvisor.com\/tools\/esp32-dev-board-wi-fi-bluetooth\/\" target=\"_blank\" rel=\"noreferrer noopener\">ESP32 DOIT DEVKIT V1 Board<\/a> (read&nbsp;<a href=\"https:\/\/makeradvisor.com\/esp32-development-boards-review-comparison\/\" target=\"_blank\" rel=\"noreferrer noopener\">Best ESP32 development boards<\/a>)<\/li><li><a href=\"https:\/\/makeradvisor.com\/tools\/oled-display-128x64-0-96-inch\/\" target=\"_blank\" rel=\"noreferrer noopener\">OLED display<\/a><\/li><li><a href=\"https:\/\/makeradvisor.com\/tools\/jumper-wires-kit-120-pieces\/\" target=\"_blank\" rel=\"noreferrer noopener\">Jumper wires<\/a><\/li><li><a href=\"https:\/\/makeradvisor.com\/tools\/mb-102-solderless-breadboard-830-points\/\" target=\"_blank\" rel=\"noreferrer noopener\">Breadboard<\/a><\/li><\/ul>\n\n\n<p>You can use the preceding links or go directly to <a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\">MakerAdvisor.com\/tools<\/a> to find all the parts for your projects at the best price!<\/p><p style=\"text-align:center;\"><a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2017\/10\/header-200.png?w=1200&#038;quality=100&#038;strip=all&#038;ssl=1\"><\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"ESP32-BLE-Server\">1) ESP32 BLE Server<\/h2>\n\n\n\n<p>In this part, we&#8217;ll set up the BLE Server that advertises a service that contains two characteristics: one for temperature and another for humidity. Those characteristics have the <em>Notify<\/em> property to notify new values to the client.<\/p>\n\n\n\n<div class=\"wp-block-image\"><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\/2021\/11\/ESP32-BLE-Server-nRF-Connect-App.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 BLE Server Connected to the nRF Connect App\" class=\"wp-image-107788\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Server-nRF-Connect-App.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Server-nRF-Connect-App.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\n<h3 class=\"wp-block-heading\">Schematic Diagram<\/h3>\n\n\n\n<p>The ESP32 BLE server will advertise characteristics with temperature and humidity from a BME280 sensor. You can use any other sensor as long as you add the required lines in the code.<\/p>\n\n\n\n<p>We\u2019re going to use I2C communication with the BME280 sensor module. For that, wire the sensor to the default ESP32&nbsp;SCL (<span class=\"rnthl rntcblue\">GPIO 22<\/span>)&nbsp;and&nbsp;SDA (<span class=\"rnthl rntcgreen\">GPIO 21<\/span>)&nbsp;pins, as shown in the following schematic diagram.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" 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&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Wiring Circuit to BME280 Schematic Diagram\" 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\n<p class=\"rntbox rntclblue\">Recommended reading: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-pinout-reference-gpios\/\">ESP32 Pinout Reference: Which GPIO pins should you use?<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Installing BME280 Libraries<\/h3>\n\n\n\n<p>As mentioned previously, we&#8217;ll advertise sensor readings from a BME280 sensor. So, you need to install the libraries to interface with the BME280 sensor.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/github.com\/adafruit\/Adafruit_BME280_Library\" target=\"_blank\" rel=\"noreferrer noopener\">Adafruit_BME280 library<\/a><\/li><li><a href=\"https:\/\/github.com\/adafruit\/Adafruit_Sensor\" target=\"_blank\" rel=\"noreferrer noopener\">Adafruit_Sensor library<\/a><\/li><\/ul>\n\n\n\n<p>You can install the libraries using the Arduino Library Manager. Go to&nbsp;<strong>Sketch&nbsp;<\/strong>&gt;&nbsp;<strong>Include Library<\/strong>&nbsp;&gt;&nbsp;<strong>Manage Libraries<\/strong>&nbsp;and search for the library name.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Installing Libraries (VS Code + PlatformIO)<\/h4>\n\n\n\n<p>If you&#8217;re using VS Code with the PlatformIO extension, copy the following to the <span class=\"rnthl rntliteral\">platformio.ini<\/span> file to include the libraries.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>lib_deps = adafruit\/Adafruit Unified Sensor @ ^1.1.4\n            adafruit\/Adafruit BME280 Library @ ^2.1.2  <\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">ESP32 BLE Server &#8211; Code<\/h3>\n\n\n\n<p>With the circuit ready and the required libraries installed, copy the following code to the Arduino IDE, or to the <span class=\"rnthl rntliteral\">main.cpp<\/span> file if you&#8217;re using VS Code.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*********\r\n  Rui Santos\r\n  Complete instructions at https:\/\/RandomNerdTutorials.com\/esp32-ble-server-client\/\r\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.\r\n  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\r\n*********\/\r\n\r\n#include &lt;BLEDevice.h&gt;\r\n#include &lt;BLEServer.h&gt;\r\n#include &lt;BLEUtils.h&gt;\r\n#include &lt;BLE2902.h&gt;\r\n#include &lt;Wire.h&gt;\r\n#include &lt;Adafruit_Sensor.h&gt;\r\n#include &lt;Adafruit_BME280.h&gt;\r\n\r\n\/\/Default Temperature is in Celsius\r\n\/\/Comment the next line for Temperature in Fahrenheit\r\n#define temperatureCelsius\r\n\r\n\/\/BLE server name\r\n#define bleServerName &quot;BME280_ESP32&quot;\r\n\r\nAdafruit_BME280 bme; \/\/ I2C\r\n\r\nfloat temp;\r\nfloat tempF;\r\nfloat hum;\r\n\r\n\/\/ Timer variables\r\nunsigned long lastTime = 0;\r\nunsigned long timerDelay = 30000;\r\n\r\nbool deviceConnected = false;\r\n\r\n\/\/ See the following for generating UUIDs:\r\n\/\/ https:\/\/www.uuidgenerator.net\/\r\n#define SERVICE_UUID &quot;91bad492-b950-4226-aa2b-4ede9fa42f59&quot;\r\n\r\n\/\/ Temperature Characteristic and Descriptor\r\n#ifdef temperatureCelsius\r\n  BLECharacteristic bmeTemperatureCelsiusCharacteristics(&quot;cba1d466-344c-4be3-ab3f-189f80dd7518&quot;, BLECharacteristic::PROPERTY_NOTIFY);\r\n  BLEDescriptor bmeTemperatureCelsiusDescriptor(BLEUUID((uint16_t)0x2902));\r\n#else\r\n  BLECharacteristic bmeTemperatureFahrenheitCharacteristics(&quot;f78ebbff-c8b7-4107-93de-889a6a06d408&quot;, BLECharacteristic::PROPERTY_NOTIFY);\r\n  BLEDescriptor bmeTemperatureFahrenheitDescriptor(BLEUUID((uint16_t)0x2902));\r\n#endif\r\n\r\n\/\/ Humidity Characteristic and Descriptor\r\nBLECharacteristic bmeHumidityCharacteristics(&quot;ca73b3ba-39f6-4ab3-91ae-186dc9577d99&quot;, BLECharacteristic::PROPERTY_NOTIFY);\r\nBLEDescriptor bmeHumidityDescriptor(BLEUUID((uint16_t)0x2903));\r\n\r\n\/\/Setup callbacks onConnect and onDisconnect\r\nclass MyServerCallbacks: public BLEServerCallbacks {\r\n  void onConnect(BLEServer* pServer) {\r\n    deviceConnected = true;\r\n  };\r\n  void onDisconnect(BLEServer* pServer) {\r\n    deviceConnected = false;\r\n  }\r\n};\r\n\r\nvoid initBME(){\r\n  if (!bme.begin(0x76)) {\r\n    Serial.println(&quot;Could not find a valid BME280 sensor, check wiring!&quot;);\r\n    while (1);\r\n  }\r\n}\r\n\r\nvoid setup() {\r\n  \/\/ Start serial communication \r\n  Serial.begin(115200);\r\n\r\n  \/\/ Init BME Sensor\r\n  initBME();\r\n\r\n  \/\/ Create the BLE Device\r\n  BLEDevice::init(bleServerName);\r\n\r\n  \/\/ Create the BLE Server\r\n  BLEServer *pServer = BLEDevice::createServer();\r\n  pServer-&gt;setCallbacks(new MyServerCallbacks());\r\n\r\n  \/\/ Create the BLE Service\r\n  BLEService *bmeService = pServer-&gt;createService(SERVICE_UUID);\r\n\r\n  \/\/ Create BLE Characteristics and Create a BLE Descriptor\r\n  \/\/ Temperature\r\n  #ifdef temperatureCelsius\r\n    bmeService-&gt;addCharacteristic(&amp;bmeTemperatureCelsiusCharacteristics);\r\n    bmeTemperatureCelsiusDescriptor.setValue(&quot;BME temperature Celsius&quot;);\r\n    bmeTemperatureCelsiusCharacteristics.addDescriptor(&amp;bmeTemperatureCelsiusDescriptor);\r\n  #else\r\n    bmeService-&gt;addCharacteristic(&amp;bmeTemperatureFahrenheitCharacteristics);\r\n    bmeTemperatureFahrenheitDescriptor.setValue(&quot;BME temperature Fahrenheit&quot;);\r\n    bmeTemperatureFahrenheitCharacteristics.addDescriptor(&amp;bmeTemperatureFahrenheitDescriptor);\r\n  #endif  \r\n\r\n  \/\/ Humidity\r\n  bmeService-&gt;addCharacteristic(&amp;bmeHumidityCharacteristics);\r\n  bmeHumidityDescriptor.setValue(&quot;BME humidity&quot;);\r\n  bmeHumidityCharacteristics.addDescriptor(new BLE2902());\r\n  \r\n  \/\/ Start the service\r\n  bmeService-&gt;start();\r\n\r\n  \/\/ Start advertising\r\n  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();\r\n  pAdvertising-&gt;addServiceUUID(SERVICE_UUID);\r\n  pServer-&gt;getAdvertising()-&gt;start();\r\n  Serial.println(&quot;Waiting a client connection to notify...&quot;);\r\n}\r\n\r\nvoid loop() {\r\n  if (deviceConnected) {\r\n    if ((millis() - lastTime) &gt; timerDelay) {\r\n      \/\/ Read temperature as Celsius (the default)\r\n      temp = bme.readTemperature();\r\n      \/\/ Fahrenheit\r\n      tempF = 1.8*temp +32;\r\n      \/\/ Read humidity\r\n      hum = bme.readHumidity();\r\n  \r\n      \/\/Notify temperature reading from BME sensor\r\n      #ifdef temperatureCelsius\r\n        static char temperatureCTemp[6];\r\n        dtostrf(temp, 6, 2, temperatureCTemp);\r\n        \/\/Set temperature Characteristic value and notify connected client\r\n        bmeTemperatureCelsiusCharacteristics.setValue(temperatureCTemp);\r\n        bmeTemperatureCelsiusCharacteristics.notify();\r\n        Serial.print(&quot;Temperature Celsius: &quot;);\r\n        Serial.print(temp);\r\n        Serial.print(&quot; \u00baC&quot;);\r\n      #else\r\n        static char temperatureFTemp[6];\r\n        dtostrf(tempF, 6, 2, temperatureFTemp);\r\n        \/\/Set temperature Characteristic value and notify connected client\r\n        bmeTemperatureFahrenheitCharacteristics.setValue(temperatureFTemp);\r\n        bmeTemperatureFahrenheitCharacteristics.notify();\r\n        Serial.print(&quot;Temperature Fahrenheit: &quot;);\r\n        Serial.print(tempF);\r\n        Serial.print(&quot; \u00baF&quot;);\r\n      #endif\r\n      \r\n      \/\/Notify humidity reading from BME\r\n      static char humidityTemp[6];\r\n      dtostrf(hum, 6, 2, humidityTemp);\r\n      \/\/Set humidity Characteristic value and notify connected client\r\n      bmeHumidityCharacteristics.setValue(humidityTemp);\r\n      bmeHumidityCharacteristics.notify();   \r\n      Serial.print(&quot; - Humidity: &quot;);\r\n      Serial.print(hum);\r\n      Serial.println(&quot; %&quot;);\r\n      \r\n      lastTime = millis();\r\n    }\r\n  }\r\n}\r\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\/BLE\/ESP32_BLE_Server.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>You can upload the code, and it will work straight away advertising its service with the temperature and humidity characteristics. Continue reading to learn how the code works, or skip to the <a href=\"#ESP32-BLE-Client\">Client section<\/a>.<\/p>\n\n\n\n<p>There are several examples showing how to use BLE with the ESP32 in the <em>Examples<\/em> section. In your Arduino IDE, go to <strong>File <\/strong>&gt; <strong>Examples<\/strong> &gt; <strong>ESP32 BLE Arduino<\/strong>. This server sketch is based on the <em>Notify <\/em>example.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Importing Libraries<\/h4>\n\n\n\n<p>The code starts by importing the required libraries.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include &lt;BLEDevice.h&gt;\n#include &lt;BLEServer.h&gt;\n#include &lt;BLEUtils.h&gt;\n#include &lt;BLE2902.h&gt;\n#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<h4 class=\"wp-block-heading\">Choosing Temperature Unit<\/h4>\n\n\n\n<p>By default, the ESP sends the temperature in Celsius degrees. You can comment the following line or delete it to send the temperature in Fahrenheit degrees.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/Comment the next line for Temperature in Fahrenheit\n#define temperatureCelsius<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">BLE Server Name<\/h4>\n\n\n\n<p>The following line defines a name for our BLE server. Leave the default BLE server name. Otherwise, the server name in the client code also needs to be changed (because they have to match).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/BLE server name\n#define bleServerName \"BME280_ESP32\"<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">BME280 Sensor<\/h4>\n\n\n\n<p>Create an <span class=\"rnthl rntliteral\">Adafruit_BME280<\/span> object called <span class=\"rnthl rntliteral\">bme<\/span> on the default ESP32 I2C pins.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Adafruit_BME280 bme; \/\/ I2C<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">temp<\/span>, <span class=\"rnthl rntliteral\">tempF<\/span> and <span class=\"rnthl rntliteral\">hum<\/span> variables will hold the temperature in Celsius degrees, the temperature in Fahrenheit degrees, and the humidity read from the BME280 sensor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>float temp;\nfloat tempF;\nfloat hum;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Other Variables<\/h4>\n\n\n\n<p>The following timer variables define how frequently we want to write to the temperature and humidity characteristic. We set the <span class=\"rnthl rntliteral\">timerDelay<\/span> variable to 30000 milliseconds (30 seconds), but you can change it.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Timer variables\nunsigned long lastTime = 0;\nunsigned long timerDelay = 30000;<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">deviceConnected<\/span> boolean variable allows us to keep track if a client is connected to the server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>bool deviceConnected = false;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">BLE UUIDs<\/h4>\n\n\n\n<p>In the next lines, we define UUIDs for the service, for the temperature characteristic in celsius, for the temperature characteristic in Fahrenheit, and for the humidity.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ https:\/\/www.uuidgenerator.net\/\n#define SERVICE_UUID \"91bad492-b950-4226-aa2b-4ede9fa42f59\"\n\n\/\/ Temperature Characteristic and Descriptor\n#ifdef temperatureCelsius\n  BLECharacteristic bmeTemperatureCelsiusCharacteristics(\"cba1d466-344c-4be3-ab3f-189f80dd7518\", BLECharacteristic::PROPERTY_NOTIFY);\n  BLEDescriptor bmeTemperatureCelsiusDescriptor(BLEUUID((uint16_t)0x2902));\n#else\n  BLECharacteristic bmeTemperatureFahrenheitCharacteristics(\"f78ebbff-c8b7-4107-93de-889a6a06d408\", BLECharacteristic::PROPERTY_NOTIFY);\n  BLEDescriptor bmeTemperatureFahrenheitDescriptor(BLEUUID((uint16_t)0x2901));\n#endif\n\n\/\/ Humidity Characteristic and Descriptor\nBLECharacteristic bmeHumidityCharacteristics(\"ca73b3ba-39f6-4ab3-91ae-186dc9577d99\", BLECharacteristic::PROPERTY_NOTIFY);\nBLEDescriptor bmeHumidityDescriptor(BLEUUID((uint16_t)0x2903));<\/code><\/pre>\n\n\n\n<p>I recommend leaving all the default UUIDs. Otherwise, you also need to change the code on the client side\u2014so the client can find the service and retrieve the characteristic values.<\/p>\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>\/\/ Start serial communication \nSerial.begin(115200);\n\n\/\/ Init BME Sensor\ninitBME();<\/code><\/pre>\n\n\n\n<p>Create a new BLE device with the BLE server name you\u2019ve defined earlier:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Create the BLE Device\nBLEDevice::init(bleServerName);<\/code><\/pre>\n\n\n\n<p>Set the BLE device as a server and assign a callback function.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Create the BLE Server\nBLEServer *pServer = BLEDevice::createServer();\npServer-&gt;setCallbacks(new MyServerCallbacks());<\/code><\/pre>\n\n\n\n<p>The callback function <span class=\"rnthl rntliteral\">MyServerCallbacks()<\/span> changes the boolean variable <span class=\"rnthl rntliteral\">deviceConnected<\/span> to <span class=\"rnthl rntliteral\">true<\/span> or <span class=\"rnthl rntliteral\">false<\/span> according to the current state of the BLE device. This means that if a client is connected to the server, the state is <span class=\"rnthl rntliteral\">true<\/span>. If the client disconnects, the boolean variable changes to <span class=\"rnthl rntliteral\">false<\/span>. Here\u2019s the part of the code that defines the <span class=\"rnthl rntliteral\">MyServerCallbacks()<\/span> function.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/Setup callbacks onConnect and onDisconnect\nclass MyServerCallbacks: public BLEServerCallbacks {\n  void onConnect(BLEServer* pServer) {\n    deviceConnected = true;\n  };\n  void onDisconnect(BLEServer* pServer) {\n    deviceConnected = false;\n  }\n};<\/code><\/pre>\n\n\n\n<p>Start a BLE service with the service UUID defined earlier.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>BLEService *bmeService = pServer-&gt;createService(SERVICE_UUID);<\/code><\/pre>\n\n\n\n<p>Then, create the temperature BLE characteristic. If you\u2019re using Celsius degrees it sets the following characteristic and descriptor:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#ifdef temperatureCelsius\n  bmeService-&gt;addCharacteristic(&amp;bmeTemperatureCelsiusCharacteristics);\n  bmeTemperatureCelsiusDescriptor.setValue(\"BME temperature Celsius\");\n  bmeTemperatureCelsiusCharacteristics.addDescriptor(new BLE2902());<\/code><\/pre>\n\n\n\n<p>Otherwise, it sets the Fahrenheit characteristic:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#else\n  bmeService-&gt;addCharacteristic(&amp;dhtTemperatureFahrenheitCharacteristics);\n  bmeTemperatureFahrenheitDescriptor.setValue(\"BME temperature Fahrenheit\");\n  bmeTemperatureFahrenheitCharacteristics.addDescriptor(new BLE2902());\n#endif  <\/code><\/pre>\n\n\n\n<p>After that, it sets the humidity characteristic:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Humidity\nbmeService-&gt;addCharacteristic(&amp;bmeHumidityCharacteristics);\nbmeHumidityDescriptor.setValue(\"BME humidity\");\nbmeHumidityCharacteristics.addDescriptor(new BLE2902());<\/code><\/pre>\n\n\n\n<p>Finally, you start the service, and the server starts the advertising so other devices can find it.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Start the service\nbmeService-&gt;start();\n\n\/\/ Start advertising\nBLEAdvertising *pAdvertising = BLEDevice::getAdvertising();\npAdvertising-&gt;addServiceUUID(SERVICE_UUID);\npServer-&gt;getAdvertising()-&gt;start();\nSerial.println(\"Waiting a client connection to notify...\");<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">loop()<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">loop()<\/span> function is fairly straightforward. You constantly check if the device is connected to a client or not. If it\u2019s connected, and the <span class=\"rnthl rntliteral\">timerDelay<\/span> has passed, it reads the current temperature and humidity.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (deviceConnected) {\n  if ((millis() - lastTime) &gt; timerDelay) {\n    \/\/ Read temperature as Celsius (the default)\n    temp = bme.readTemperature();\n    \/\/ Fahrenheit\n    tempF = temp*1.8 +32;\n    \/\/ Read humidity\n    hum = bme.readHumidity();<\/code><\/pre>\n\n\n\n<p>If you\u2019re using temperature in Celsius it runs the following code section. First, it converts the temperature to a char variable (<span class=\"rnthl rntliteral\">temperatureCTemp<\/span> variable). We must convert the temperature to a char variable type to use it in the <span class=\"rnthl rntliteral\">setValue()<\/span> function.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>static char temperatureCTemp&#091;6];\ndtostrf(temp, 6, 2, temperatureCTemp);<\/code><\/pre>\n\n\n\n<p>Then, it sets the <span class=\"rnthl rntliteral\">bmeTemperatureCelsiusCharacteristic<\/span> value to the new temperature value (<span class=\"rnthl rntliteral\">temperatureCTemp<\/span>) using the <span class=\"rnthl rntliteral\">setValue()<\/span> function. After settings the new value, we can notify the connected client using the <span class=\"rnthl rntliteral\">notify()<\/span> function.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/Set temperature Characteristic value and notify connected client\nbmeTemperatureCelsiusCharacteristics.setValue(temperatureCTemp);\nbmeTemperatureCelsiusCharacteristics.notify();<\/code><\/pre>\n\n\n\n<p>We follow a similar procedure for the Temperature in Fahrenheit.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#else\n    static char temperatureFTemp&#091;6];\n    dtostrf(f, 6, 2, temperatureFTemp);\n    \/\/Set temperature Characteristic value and notify connected client\n    bmeTemperatureFahrenheitCharacteristics.setValue(tempF);\n    bmeTemperatureFahrenheitCharacteristics.notify();\n    Serial.print(\"Temperature Fahrenheit: \");\n    Serial.print(tempF);\n    Serial.print(\" *F\");\n#endif<\/code><\/pre>\n\n\n\n<p>Sending the humidity also uses the same process.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/Notify humidity reading from DHT\nstatic char humidityTemp&#091;6];\ndtostrf(hum, 6, 2, humidityTemp);\n\/\/Set humidity Characteristic value and notify connected client\nbmeHumidityCharacteristics.setValue(humidityTemp);\nbmeHumidityCharacteristics.notify();   \nSerial.print(\" - Humidity: \");\nSerial.print(hum);\nSerial.println(\" %\");<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Testing the ESP32 BLE Server<\/h3>\n\n\n\n<p>Upload the code to your board and then, open the Serial Monitor. It will display a message as shown below.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"632\" height=\"411\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Server-Started-Serial-Monitor.png?resize=632%2C411&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 BLE Server Starts Serial Monitor\" class=\"wp-image-107756\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Server-Started-Serial-Monitor.png?w=632&amp;quality=100&amp;strip=all&amp;ssl=1 632w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Server-Started-Serial-Monitor.png?resize=300%2C195&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 632px) 100vw, 632px\" \/><\/figure><\/div>\n\n\n\n<p>Then, you can test if the BLE server is working as expected by using a BLE scan application on your smartphone like <strong>nRF Connect<\/strong>. This application is available for <a href=\"https:\/\/play.google.com\/store\/apps\/details?id=no.nordicsemi.android.mcp&amp;hl=en&amp;gl=US\" target=\"_blank\" rel=\"noreferrer noopener\">Android <\/a>and <a href=\"https:\/\/apps.apple.com\/us\/app\/nrf-connect-for-mobile\/id1054362403\" target=\"_blank\" rel=\"noreferrer noopener\">iOS<\/a>.<\/p>\n\n\n\n<p>After installing the application, enable Bluetooth on your smartphone. Open the nRF Connect app and click on the Scan button. It will find all Bluetooth nearby devices, including your <strong>BME280_ESP32<\/strong> device (it is the BLE server name you defined on the code).<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"450\" height=\"390\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/Scan-ESP32-BLE-Device-nRF-Connect-App.png?resize=450%2C390&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 BLE Server Scanner App\" class=\"wp-image-107758\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/Scan-ESP32-BLE-Device-nRF-Connect-App.png?w=450&amp;quality=100&amp;strip=all&amp;ssl=1 450w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/Scan-ESP32-BLE-Device-nRF-Connect-App.png?resize=300%2C260&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 450px) 100vw, 450px\" \/><\/figure><\/div>\n\n\n\n<p>Connect to your BME280_ESP32 device and then, select the client tab (the interface might be slightly different). You can check that it advertises the service with the UUID we defined in the code, as well as the temperature and humidity characteristics. Notice that those characteristics have the <em>Notify<\/em> property.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"450\" height=\"974\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Server-Characteristics-nRF-Connect.png?resize=450%2C974&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 BLE Server Characteristics nRF Connect App\" class=\"wp-image-107759\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Server-Characteristics-nRF-Connect.png?w=450&amp;quality=100&amp;strip=all&amp;ssl=1 450w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Server-Characteristics-nRF-Connect.png?resize=139%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 139w\" sizes=\"(max-width: 450px) 100vw, 450px\" \/><\/figure><\/div>\n\n\n\n<p>Your ESP32 BLE Server is ready!<\/p>\n\n\n\n<p>Go to the next section to create an ESP32 client that connects to the server to get access to the temperature and humidity characteristics and get the readings to display them on an OLED display.<\/p>\n\n\n\n<hr class=\"wp-block-separator is-style-wide\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"ESP32-BLE-Client\">2) ESP32 BLE Client<\/h2>\n\n\n\n<p>In this section, we&#8217;ll create the ESP32 BLE client that will establish a connection with the ESP32 BLE server, and display the readings on an OLED display.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<p>The ESP32 BLE client is connected to an OLED display. The display shows the readings received via Bluetooth.<\/p>\n\n\n\n<p>Wire your OLED display to the ESP32 by following the next schematic diagram. The SCL pin connects to <span class=\"rnthl rntclgray\">GPIO 22<\/span> and the SDA pin to <span class=\"rnthl rntcyellow\">GPIO 21<\/span>.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"873\" height=\"685\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/05\/ESP32_OLED.png?resize=873%2C685&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Wiring Circuit to OLED SSD1306 Schematic Diagram\" class=\"wp-image-85566\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/05\/ESP32_OLED.png?w=873&amp;quality=100&amp;strip=all&amp;ssl=1 873w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/05\/ESP32_OLED.png?resize=300%2C235&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2019\/05\/ESP32_OLED.png?resize=768%2C603&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 873px) 100vw, 873px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Installing the SSD1306, GFX and BusIO Libraries<\/h3>\n\n\n\n<p>You need to install the following libraries to interface with the OLED display:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/github.com\/adafruit\/Adafruit_SSD1306\" target=\"_blank\" rel=\"noreferrer noopener\">Adafruit_SSD1306 library<\/a><\/li><li><a href=\"https:\/\/github.com\/adafruit\/Adafruit-GFX-Library\" target=\"_blank\" rel=\"noreferrer noopener\">Adafruit GFX library<\/a><\/li><li><a href=\"https:\/\/github.com\/adafruit\/Adafruit_BusIO\" target=\"_blank\" rel=\"noreferrer noopener\">Adafruit BusIO library<\/a><\/li><\/ul>\n\n\n\n<p>To install the libraries, go&nbsp;<strong>Sketch<\/strong>&gt;&nbsp;<strong>Include Library<\/strong>&nbsp;&gt;&nbsp;<strong>Manage Libraries<\/strong>, and search for the libraries\u2019 names.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Installing Libraries (VS Code + PlatformIO)<\/h4>\n\n\n\n<p>If you&#8217;re using VS Code with the PlatformIO extension, copy the following to the <span class=\"rnthl rntliteral\">platformio.ini<\/span> file to include the libraries.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>lib_deps = \n\tadafruit\/Adafruit GFX Library@^1.10.12\n\tadafruit\/Adafruit SSD1306@^2.4.6\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">ESP32 BLE Client &#8211; Code<\/h3>\n\n\n\n<p>Copy the BLE client Sketch to your Arduino IDE or to the <span class=\"rnthl rntliteral\">main.cpp<\/span> file if you&#8217;re using VS Code with PlatformIO.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*********\r\n  Rui Santos\r\n  Complete instructions at https:\/\/RandomNerdTutorials.com\/esp32-ble-server-client\/\r\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.\r\n  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\r\n*********\/\r\n\r\n#include &quot;BLEDevice.h&quot;\r\n#include &lt;Wire.h&gt;\r\n#include &lt;Adafruit_SSD1306.h&gt;\r\n#include &lt;Adafruit_GFX.h&gt;\r\n\r\n\/\/Default Temperature is in Celsius\r\n\/\/Comment the next line for Temperature in Fahrenheit\r\n#define temperatureCelsius\r\n\r\n\/\/BLE Server name (the other ESP32 name running the server sketch)\r\n#define bleServerName &quot;BME280_ESP32&quot;\r\n\r\n\/* UUID's of the service, characteristic that we want to read*\/\r\n\/\/ BLE Service\r\nstatic BLEUUID bmeServiceUUID(&quot;91bad492-b950-4226-aa2b-4ede9fa42f59&quot;);\r\n\r\n\/\/ BLE Characteristics\r\n#ifdef temperatureCelsius\r\n  \/\/Temperature Celsius Characteristic\r\n  static BLEUUID temperatureCharacteristicUUID(&quot;cba1d466-344c-4be3-ab3f-189f80dd7518&quot;);\r\n#else\r\n  \/\/Temperature Fahrenheit Characteristic\r\n  static BLEUUID temperatureCharacteristicUUID(&quot;f78ebbff-c8b7-4107-93de-889a6a06d408&quot;);\r\n#endif\r\n\r\n\/\/ Humidity Characteristic\r\nstatic BLEUUID humidityCharacteristicUUID(&quot;ca73b3ba-39f6-4ab3-91ae-186dc9577d99&quot;);\r\n\r\n\/\/Flags stating if should begin connecting and if the connection is up\r\nstatic boolean doConnect = false;\r\nstatic boolean connected = false;\r\n\r\n\/\/Address of the peripheral device. Address will be found during scanning...\r\nstatic BLEAddress *pServerAddress;\r\n \r\n\/\/Characteristicd that we want to read\r\nstatic BLERemoteCharacteristic* temperatureCharacteristic;\r\nstatic BLERemoteCharacteristic* humidityCharacteristic;\r\n\r\n\/\/Activate notify\r\nconst uint8_t notificationOn[] = {0x1, 0x0};\r\nconst uint8_t notificationOff[] = {0x0, 0x0};\r\n\r\n#define SCREEN_WIDTH 128 \/\/ OLED display width, in pixels\r\n#define SCREEN_HEIGHT 64 \/\/ OLED display height, in pixels\r\n\r\n\/\/Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)\r\nAdafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &amp;Wire, -1);\r\n\r\n\/\/Variables to store temperature and humidity\r\nchar* temperatureChar;\r\nchar* humidityChar;\r\n\r\n\/\/Flags to check whether new temperature and humidity readings are available\r\nboolean newTemperature = false;\r\nboolean newHumidity = false;\r\n\r\n\/\/Connect to the BLE Server that has the name, Service, and Characteristics\r\nbool connectToServer(BLEAddress pAddress) {\r\n   BLEClient* pClient = BLEDevice::createClient();\r\n \r\n  \/\/ Connect to the remove BLE Server.\r\n  pClient-&gt;connect(pAddress);\r\n  Serial.println(&quot; - Connected to server&quot;);\r\n \r\n  \/\/ Obtain a reference to the service we are after in the remote BLE server.\r\n  BLERemoteService* pRemoteService = pClient-&gt;getService(bmeServiceUUID);\r\n  if (pRemoteService == nullptr) {\r\n    Serial.print(&quot;Failed to find our service UUID: &quot;);\r\n    Serial.println(bmeServiceUUID.toString().c_str());\r\n    return (false);\r\n  }\r\n \r\n  \/\/ Obtain a reference to the characteristics in the service of the remote BLE server.\r\n  temperatureCharacteristic = pRemoteService-&gt;getCharacteristic(temperatureCharacteristicUUID);\r\n  humidityCharacteristic = pRemoteService-&gt;getCharacteristic(humidityCharacteristicUUID);\r\n\r\n  if (temperatureCharacteristic == nullptr || humidityCharacteristic == nullptr) {\r\n    Serial.print(&quot;Failed to find our characteristic UUID&quot;);\r\n    return false;\r\n  }\r\n  Serial.println(&quot; - Found our characteristics&quot;);\r\n \r\n  \/\/Assign callback functions for the Characteristics\r\n  temperatureCharacteristic-&gt;registerForNotify(temperatureNotifyCallback);\r\n  humidityCharacteristic-&gt;registerForNotify(humidityNotifyCallback);\r\n  return true;\r\n}\r\n\r\n\/\/Callback function that gets called, when another device's advertisement has been received\r\nclass MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {\r\n  void onResult(BLEAdvertisedDevice advertisedDevice) {\r\n    if (advertisedDevice.getName() == bleServerName) { \/\/Check if the name of the advertiser matches\r\n      advertisedDevice.getScan()-&gt;stop(); \/\/Scan can be stopped, we found what we are looking for\r\n      pServerAddress = new BLEAddress(advertisedDevice.getAddress()); \/\/Address of advertiser is the one we need\r\n      doConnect = true; \/\/Set indicator, stating that we are ready to connect\r\n      Serial.println(&quot;Device found. Connecting!&quot;);\r\n    }\r\n  }\r\n};\r\n \r\n\/\/When the BLE Server sends a new temperature reading with the notify property\r\nstatic void temperatureNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, \r\n                                        uint8_t* pData, size_t length, bool isNotify) {\r\n  \/\/store temperature value\r\n  temperatureChar = (char*)pData;\r\n  newTemperature = true;\r\n}\r\n\r\n\/\/When the BLE Server sends a new humidity reading with the notify property\r\nstatic void humidityNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, \r\n                                    uint8_t* pData, size_t length, bool isNotify) {\r\n  \/\/store humidity value\r\n  humidityChar = (char*)pData;\r\n  newHumidity = true;\r\n  Serial.print(newHumidity);\r\n}\r\n\r\n\/\/function that prints the latest sensor readings in the OLED display\r\nvoid printReadings(){\r\n  \r\n  display.clearDisplay();  \r\n  \/\/ display temperature\r\n  display.setTextSize(1);\r\n  display.setCursor(0,0);\r\n  display.print(&quot;Temperature: &quot;);\r\n  display.setTextSize(2);\r\n  display.setCursor(0,10);\r\n  display.print(temperatureChar);\r\n  display.setTextSize(1);\r\n  display.cp437(true);\r\n  display.write(167);\r\n  display.setTextSize(2);\r\n  Serial.print(&quot;Temperature:&quot;);\r\n  Serial.print(temperatureChar);\r\n  #ifdef temperatureCelsius\r\n    \/\/Temperature Celsius\r\n    display.print(&quot;C&quot;);\r\n    Serial.print(&quot;C&quot;);\r\n  #else\r\n    \/\/Temperature Fahrenheit\r\n    display.print(&quot;F&quot;);\r\n    Serial.print(&quot;F&quot;);\r\n  #endif\r\n\r\n  \/\/display humidity \r\n  display.setTextSize(1);\r\n  display.setCursor(0, 35);\r\n  display.print(&quot;Humidity: &quot;);\r\n  display.setTextSize(2);\r\n  display.setCursor(0, 45);\r\n  display.print(humidityChar);\r\n  display.print(&quot;%&quot;);\r\n  display.display();\r\n  Serial.print(&quot; Humidity:&quot;);\r\n  Serial.print(humidityChar); \r\n  Serial.println(&quot;%&quot;);\r\n}\r\n\r\nvoid setup() {\r\n  \/\/OLED display setup\r\n  \/\/ SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally\r\n  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { \/\/ Address 0x3C for 128x32\r\n    Serial.println(F(&quot;SSD1306 allocation failed&quot;));\r\n    for(;;); \/\/ Don't proceed, loop forever\r\n  }\r\n  display.clearDisplay();\r\n  display.setTextSize(2);\r\n  display.setTextColor(WHITE,0);\r\n  display.setCursor(0,25);\r\n  display.print(&quot;BLE Client&quot;);\r\n  display.display();\r\n  \r\n  \/\/Start serial communication\r\n  Serial.begin(115200);\r\n  Serial.println(&quot;Starting Arduino BLE Client application...&quot;);\r\n\r\n  \/\/Init BLE device\r\n  BLEDevice::init(&quot;&quot;);\r\n \r\n  \/\/ Retrieve a Scanner and set the callback we want to use to be informed when we\r\n  \/\/ have detected a new device.  Specify that we want active scanning and start the\r\n  \/\/ scan to run for 30 seconds.\r\n  BLEScan* pBLEScan = BLEDevice::getScan();\r\n  pBLEScan-&gt;setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());\r\n  pBLEScan-&gt;setActiveScan(true);\r\n  pBLEScan-&gt;start(30);\r\n}\r\n\r\nvoid loop() {\r\n  \/\/ If the flag &quot;doConnect&quot; is true then we have scanned for and found the desired\r\n  \/\/ BLE Server with which we wish to connect.  Now we connect to it.  Once we are\r\n  \/\/ connected we set the connected flag to be true.\r\n  if (doConnect == true) {\r\n    if (connectToServer(*pServerAddress)) {\r\n      Serial.println(&quot;We are now connected to the BLE Server.&quot;);\r\n      \/\/Activate the Notify property of each Characteristic\r\n      temperatureCharacteristic-&gt;getDescriptor(BLEUUID((uint16_t)0x2902))-&gt;writeValue((uint8_t*)notificationOn, 2, true);\r\n      humidityCharacteristic-&gt;getDescriptor(BLEUUID((uint16_t)0x2902))-&gt;writeValue((uint8_t*)notificationOn, 2, true);\r\n      connected = true;\r\n    } else {\r\n      Serial.println(&quot;We have failed to connect to the server; Restart your device to scan for nearby BLE server again.&quot;);\r\n    }\r\n    doConnect = false;\r\n  }\r\n  \/\/if new temperature readings are available, print in the OLED\r\n  if (newTemperature &amp;&amp; newHumidity){\r\n    newTemperature = false;\r\n    newHumidity = false;\r\n    printReadings();\r\n  }\r\n  delay(1000); \/\/ Delay a second between loops.\r\n}\r\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\/BLE\/ESP32_BLE_Client.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/rntlab.com\/wp-content\/uploads\/2018\/03\/activate_notify.jpg\"><\/a><\/p>\n\n\n\n<p>Continue reading to learn how the code works or skip to the <a href=\"#demonstration\">Demonstration <\/a>section.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Importing libraries<\/h4>\n\n\n\n<p>You start by importing the required libraries:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include \"BLEDevice.h\"\n#include &lt;Wire.h&gt;\n#include &lt;Adafruit_SSD1306.h&gt;\n#include &lt;Adafruit_GFX.h&gt;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Choosing temperature unit<\/h4>\n\n\n\n<p>By default the client will receive the temperature in Celsius degrees, if you comment the following line or delete it, it will start receiving the temperature in Fahrenheit degrees.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/Default Temperature is in Celsius\n\/\/Comment the next line for Temperature in Fahrenheit\n#define temperatureCelsius<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">BLE Server Name and UUIDs<\/h4>\n\n\n\n<p>Then, define the BLE server name that we want to connect to and the service and characteristic UUIDs that we want to read. Leave the default BLE server name and UUIDs to match the ones defined in the server sketch.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/BLE Server name (the other ESP32 name running the server sketch)\n#define bleServerName \"BME280_ESP32\"\n\n\/* UUID's of the service, characteristic that we want to read*\/\n\/\/ BLE Service\nstatic BLEUUID bmeServiceUUID(\"91bad492-b950-4226-aa2b-4ede9fa42f59\");\n\n\/\/ BLE Characteristics\n#ifdef temperatureCelsius\n  \/\/Temperature Celsius Characteristic\n  static BLEUUID temperatureCharacteristicUUID(\"cba1d466-344c-4be3-ab3f-189f80dd7518\");\n#else\n  \/\/Temperature Fahrenheit Characteristic\n  static BLEUUID temperatureCharacteristicUUID(\"f78ebbff-c8b7-4107-93de-889a6a06d408\");\n#endif\n\n\/\/ Humidity Characteristic\nstatic BLEUUID humidityCharacteristicUUID(\"ca73b3ba-39f6-4ab3-91ae-186dc9577d99\");\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Declaring variables<\/h4>\n\n\n\n<p>Then, you need to declare some variables that will be used later with Bluetooth to check whether we&#8217;re connected to the server or not.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/Flags stating if should begin connecting and if the connection is up\nstatic boolean doConnect = false;\nstatic boolean connected = false;<\/code><\/pre>\n\n\n\n<p>Create a variable of type <span class=\"rnthl rntliteral\">BLEAddress<\/span> that refers to the address of the server we want to connect. This address will be found during scanning.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/Address of the peripheral device. Address will be found during scanning...\nstatic BLEAddress *pServerAddress;<\/code><\/pre>\n\n\n\n<p>Set the characteristics we want to read (temperature and humidity).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/Characteristicd that we want to read\nstatic BLERemoteCharacteristic* temperatureCharacteristic;\nstatic BLERemoteCharacteristic* humidityCharacteristic;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">OLED Display<\/h4>\n\n\n\n<p>You also need to declare some variables to work with the OLED. Define the OLED width and height:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define SCREEN_WIDTH 128 \/\/ OLED display width, in pixels\n#define SCREEN_HEIGHT 64 \/\/ OLED display height, in pixels<\/code><\/pre>\n\n\n\n<p>Instantiate the OLED display with the width and height defined earlier.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &amp;Wire);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Temperature and Humidity Variables<\/h4>\n\n\n\n<p>Define char variables to hold the temperature and humidity values received by the server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/Variables to store temperature and humidity\nchar* temperatureChar;\nchar* humidityChar;<\/code><\/pre>\n\n\n\n<p>The following variables are used to check whether new temperature and humidity readings are available and if it is time to update the OLED display.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/Flags to check whether new temperature and humidity readings are available\nboolean newTemperature = false;\nboolean newHumidity = false;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">printReadings()<\/h4>\n\n\n\n<p>We created a function called <span class=\"rnthl rntliteral\">printReadings()<\/span> that displays the temperature and humidity readings on the OLED display.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void printReadings(){\n  \n  display.clearDisplay();  \n  \/\/ display temperature\n  display.setTextSize(1);\n  display.setCursor(0,0);\n  display.print(\"Temperature: \");\n  display.setTextSize(2);\n  display.setCursor(0,10);\n  display.print(temperatureChar);\n  display.print(\" \");\n  display.setTextSize(1);\n  display.cp437(true);\n  display.write(167);\n  display.setTextSize(2);\n  Serial.print(\"Temperature:\");\n  Serial.print(temperatureChar);\n  #ifdef temperatureCelsius\n    \/\/Temperature Celsius\n    display.print(\"C\");\n    Serial.print(\"C\");\n  #else\n    \/\/Temperature Fahrenheit\n    display.print(\"F\");\n    Serial.print(\"F\");\n  #endif\n\n  \/\/display humidity\n  display.setTextSize(1);\n  display.setCursor(0, 35);\n  display.print(\"Humidity: \");\n  display.setTextSize(2);\n  display.setCursor(0, 45);\n  display.print(humidityChar);\n  display.print(\"%\");\n  display.display();\n  Serial.print(\" Humidity:\");\n  Serial.print(humidityChar); \n  Serial.println(\"%\");\n}<\/code><\/pre>\n\n\n\n<p class=\"rntbox rntclblue\"><strong>Recommended reading: <\/strong><a href=\"https:\/\/randomnerdtutorials.com\/esp32-ssd1306-oled-display-arduino-ide\/\">ESP32 OLED Display with Arduino IDE<\/a><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">setup()<\/h4>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">setup()<\/span>, start the OLED display.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/OLED display setup\n\/\/ SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally\nif(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { \/\/ Address 0x3C for 128x32\n  Serial.println(F(\"SSD1306 allocation failed\"));\n  for(;;); \/\/ Don't proceed, loop forever\n}<\/code><\/pre>\n\n\n\n<p>Then, print a message in the first line saying \u201cBME SENSOR\u201d.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>display.clearDisplay();\ndisplay.setTextSize(2);\ndisplay.setTextColor(WHITE,0);\ndisplay.setCursor(0,25);\ndisplay.print(\"BLE Client\");\ndisplay.display();<\/code><\/pre>\n\n\n\n<p>Start the serial communication at a baud rate of 115200.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.begin(115200);<\/code><\/pre>\n\n\n\n<p>And initialize the BLE device.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/Init BLE device\nBLEDevice::init(\"\");<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Scan nearby devices<\/h4>\n\n\n\n<p>The following methods scan for nearby devices.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Retrieve a Scanner and set the callback we want to use to be informed when we\n\/\/ have detected a new device.  Specify that we want active scanning and start the\n\/\/ scan to run for 30 seconds.\nBLEScan* pBLEScan = BLEDevice::getScan();\npBLEScan-&gt;setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());\npBLEScan-&gt;setActiveScan(true);\npBLEScan-&gt;start(30);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">MyAdvertisedDeviceCallbacks() function<\/h4>\n\n\n\n<p>Note that the <span class=\"rnthl rntliteral\">MyAdvertisedDeviceCallbacks()<\/span> function, upon finding a BLE device, checks if the device found has the right BLE server name. If it has, it stops the scan and changes the <span class=\"rnthl rntliteral\">doConnect<\/span> boolean variable to <span class=\"rnthl rntliteral\">true<\/span>. This way we know that we found the server we\u2019re looking for, and we can start establishing a connection.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/Callback function that gets called, when another device's advertisement has been received\nclass MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {\n  void onResult(BLEAdvertisedDevice advertisedDevice) {\n    if (advertisedDevice.getName() == bleServerName) { \/\/Check if the name of the advertiser matches\n      advertisedDevice.getScan()-&gt;stop(); \/\/Scan can be stopped, we found what we are looking for\n      pServerAddress = new BLEAddress(advertisedDevice.getAddress()); \/\/Address of advertiser is the one we need\n      doConnect = true; \/\/Set indicator, stating that we are ready to connect\n      Serial.println(\"Device found. Connecting!\");\n    }\n  }\n};<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Connect to the server<\/h4>\n\n\n\n<p>If the <span class=\"rnthl rntliteral\">doConnect<\/span> variable is <span class=\"rnthl rntliteral\">true<\/span>, it tries to connect to the BLE server. The <span class=\"rnthl rntliteral\">connectToServer()<\/span> function handles the connection between the client and the server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/Connect to the BLE Server that has the name, Service, and Characteristics\nbool connectToServer(BLEAddress pAddress) {\n   BLEClient* pClient = BLEDevice::createClient();\n \n  \/\/ Connect to the remove BLE Server.\n  pClient-&gt;connect(pAddress);\n  Serial.println(\" - Connected to server\");\n \n  \/\/ Obtain a reference to the service we are after in the remote BLE server.\n  BLERemoteService* pRemoteService = pClient-&gt;getService(bmeServiceUUID);\n  if (pRemoteService == nullptr) {\n    Serial.print(\"Failed to find our service UUID: \");\n    Serial.println(bmeServiceUUID.toString().c_str());\n    return (false);\n  }\n \n  \/\/ Obtain a reference to the characteristics in the service of the remote BLE server.\n  temperatureCharacteristic = pRemoteService-&gt;getCharacteristic(temperatureCharacteristicUUID);\n  humidityCharacteristic = pRemoteService-&gt;getCharacteristic(humidityCharacteristicUUID);\n\n  if (temperatureCharacteristic == nullptr || humidityCharacteristic == nullptr) {\n    Serial.print(\"Failed to find our characteristic UUID\");\n    return false;\n  }\n  Serial.println(\" - Found our characteristics\");\n \n  \/\/Assign callback functions for the Characteristics\n  temperatureCharacteristic-&gt;registerForNotify(temperatureNotifyCallback);\n  humidityCharacteristic-&gt;registerForNotify(humidityNotifyCallback);\n  return true;\n}<\/code><\/pre>\n\n\n\n<p>It also assigns a callback function responsible to handle what happens when a new value is received.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/Assign callback functions for the Characteristics\ntemperatureCharacteristic-&gt;registerForNotify(temperatureNotifyCallback);\nhumidityCharacteristic-&gt;registerForNotify(humidityNotifyCallback);<\/code><\/pre>\n\n\n\n<p>After the BLE client is connected to the server, you need to active the <em>notify <\/em>property for each characteristic. For that, use the <span class=\"rnthl rntliteral\">writeValue()<\/span> method on the descriptor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (connectToServer(*pServerAddress)) {\n  Serial.println(\"We are now connected to the BLE Server.\");\n  \/\/Activate the Notify property of each Characteristic\n  temperatureCharacteristic-&gt;getDescriptor(BLEUUID((uint16_t)0x2902))-&gt;writeValue((uint8_t*)notificationOn, 2, true);\n  humidityCharacteristic-&gt;getDescriptor(BLEUUID((uint16_t)0x2902))-&gt;writeValue((uint8_t*)notificationOn, 2, true);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Notify new values<\/h4>\n\n\n\n<p>When the client receives a new notify value, it will call these two functions: <span class=\"rnthl rntliteral\">temperatureNotifyCallback()<\/span> and <span class=\"rnthl rntliteral\">humidityNotifyCallback()<\/span> that are responsible for retrieving the new value, update the OLED with the new readings and print them on the Serial Monitor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/When the BLE Server sends a new temperature reading with the notify property\nstatic void temperatureNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, \n                                        uint8_t* pData, size_t length, bool isNotify) {\n  \/\/store temperature value\n  temperatureChar = (char*)pData;\n  newTemperature = true;\n}<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/When the BLE Server sends a new humidity reading with the notify property\nstatic void humidityNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, \n                                    uint8_t* pData, size_t length, bool isNotify) {\n  \/\/store humidity value\n  humidityChar = (char*)pData;\n  newHumidity = true;\n  Serial.print(newHumidity);\n}<\/code><\/pre>\n\n\n\n<p>These two previous functions are executed every time the BLE server notifies the client with a new value, which happens every 30 seconds. These functions save the values received on the <span class=\"rnthl rntliteral\">temperatureChar<\/span> and <span class=\"rnthl rntliteral\">humidityChar<\/span> variables. These also change the <span class=\"rnthl rntliteral\">newTemperature<\/span> and <span class=\"rnthl rntliteral\">newHumidity<\/span> variables to <span class=\"rnthl rntliteral\">true<\/span>, so that we know we\u2019ve received new readings.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Display new temperature and humidity readings<\/h4>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">loop()<\/span>, there is an if statement that checks if new readings are available. If there are new readings, we se the <span class=\"rnthl rntliteral\">newTemperature<\/span> and <span class=\"rnthl rntliteral\">newHumidity<\/span> variables to <span class=\"rnthl rntliteral\">false<\/span>, so that we are able to receive new readings later on. Then, we call the <span class=\"rnthl rntliteral\">printReadings()<\/span> function to display the readings on the OLED.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/if new temperature readings are available, print in the OLED\nif (newTemperature &amp;&amp; newHumidity){\n  newTemperature = false;\n  newHumidity = false;\n  printReadings();\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"demonstration\">Testing the Project<\/h3>\n\n\n\n<p>That\u2019s it for the code. You can upload it to your ESP32 board.<\/p>\n\n\n\n<p>Once the code is uploaded. Power the ESP32 BLE server, then power the ESP32 with the client sketch. The client starts scanning nearby devices, and when it finds the other ESP32, it establishes a Bluetooth connection. Every 30 seconds, it updates the display with the latest readings.<\/p>\n\n\n\n<div class=\"wp-block-image\"><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\/2021\/11\/ESP32-BLE-Server-nRF-Connect-App-f.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 BLE Client Server OLED Display Demonstration\" class=\"wp-image-107790\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Server-nRF-Connect-App-f.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Server-nRF-Connect-App-f.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\n<p class=\"rntbox rntcred\"><strong>Important: <\/strong> don&#8217;t forget to disconnect your smartphone from the BLE server. Otherwise, the ESP32 BLE Client won&#8217;t be able to connect to the server.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"632\" height=\"461\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Client-Connected-to-Server-Serial-Monitor-f.png?resize=632%2C461&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 BLE Client Connected to ESP32 BLE Server Serial Monitor\" class=\"wp-image-107769\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Client-Connected-to-Server-Serial-Monitor-f.png?w=632&amp;quality=100&amp;strip=all&amp;ssl=1 632w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/11\/ESP32-BLE-Client-Connected-to-Server-Serial-Monitor-f.png?resize=300%2C219&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 632px) 100vw, 632px\" \/><\/figure><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>In this tutorial, you learned how to create a BLE Server and a BLE Client with the ESP32. You learned how to set new temperature and humidity values on the BLE server characteristics. Then, other BLE devices (clients) can connect to that server and read those characteristic values to get the latest temperature and humidity values. Those characteristics have the <em>notify <\/em>property, so that the client is notified whenever there&#8217;s a new value.<\/p>\n\n\n\n<p>Using BLE is another communication protocol you can use with the ESP32 boards besides Wi-Fi. We hope you found this tutorial useful. We have tutorials for other communication protocols that you may find useful.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-bluetooth-classic-arduino-ide\/\">ESP32 Bluetooth Classic with Arduino IDE \u2013 Getting Started<\/a><\/li><li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-useful-wi-fi-functions-arduino\/\">ESP32 Useful Wi-Fi Library Functions (Arduino IDE)<\/a><\/li><li><a href=\"https:\/\/randomnerdtutorials.com\/esp-mesh-esp32-esp8266-painlessmesh\/\">ESP-MESH with ESP32 and ESP8266: Getting Started (painlessMesh library)<\/a><\/li><li><a href=\"https:\/\/randomnerdtutorials.com\/esp-now-esp32-arduino-ide\/\">Getting Started with ESP-NOW (ESP32 with Arduino IDE)<\/a><\/li><\/ul>\n\n\n\n<p>Learn more about the ESP32 with our resources:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/randomnerdtutorials.com\/learn-esp32-with-arduino-ide\/\">Learn ESP32 with Arduino IDE (eBook + Video Course)<\/a><\/li><li><a href=\"https:\/\/randomnerdtutorials.com\/projects-esp32\/\">More ESP32 projects and tutorials\u2026<\/a><\/li><\/ul>\n\n\n\n<p><a href=\"https:\/\/rntlab.com\/wp-content\/uploads\/2018\/03\/Screenshot_20180315-162241.jpg\"><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to make a BLE (Bluetooth Low Energy) connection between two ESP32 boards. One ESP32 is going to be the server, and the other ESP32 will be the client. &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP32 BLE Server and Client (Bluetooth Low Energy)\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp32-ble-server-client\/#more-107720\" aria-label=\"Read more about ESP32 BLE Server and Client (Bluetooth Low Energy)\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":5,"featured_media":107770,"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-107720","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\/2021\/11\/ESP32-BLE-Client-Server.jpg?fit=1280%2C720&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/107720","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=107720"}],"version-history":[{"count":31,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/107720\/revisions"}],"predecessor-version":[{"id":107815,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/107720\/revisions\/107815"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/107770"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=107720"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=107720"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=107720"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}