MakerGram Logo

    MakerGram

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Popular
    • Tags
    • Users
    • Groups

    Automatic pairing of ESP32 using BLE

    Arduino
    esp32 masterslaveco ble bluetooth
    2
    17
    14073
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • kowshik1729
      kowshik1729 last edited by salmanfaris

      Hey guys...I've been working on a project where I need to pair two ESP32's using their BLE just as how we do for Master slave configuration of two HC-05 Bluetooth modules.....Can anyone please help me out with the code part...!!...Thank you so much in advance

      1 Reply Last reply Reply Quote 0
      • salmanfaris
        salmanfaris last edited by salmanfaris

        Hi @kowshik1729 ,

        Using Bluetooth Classic (like HC-05..etc ) is much simpler than Bluetooth Low Energy (like esp32, nRF52..etc).

        Understanding Bluetooth Low Energy (BLE)
        The Bluetooth Low Energy, as the name indicates consumes less power than classic Bluetooth. It is achieved by sending data as needed with pre-defined periodic updates. But unlike classic Bluetooth, it is not used to transfer Files or Music.

        GAP
        GAP is an acronym for the Generic Access Profile, and it controls connections and advertising in Bluetooth. GAP is what makes your device visible to the outside world, and determines how two devices can (or can't) interact with each other.

        Device Roles
        GAP defines various roles for devices, but the two key concepts to keep in mind are Central devices and Peripheral devices.

        • Peripheral devices are small, low power, resource-constrained devices that can connect to a much more powerful central device. Peripheral devices are things like a heart rate monitor, a BLE enabled proximity tag, etc.

        • Central devices are usually the mobile phone or tablet that you connect to with far more processing power and memory.

        Once you establish a connection between your peripheral and a central device, the advertising process will generally stop and you will typically no longer be able to send advertising packets out anymore, and you will use GATT services and characteristics to communicate in both directions.

        GATT
        GATT is an acronym for the Generic Attribute Profile, and it defines the way that two Bluetooth Low Energy devices transfer data back and forth using concepts called Services and Characteristics. It makes use of a generic data protocol called the Attribute Protocol (ATT), which is used to store Services.

        Note : GATT comes into play once a dedicated connection is established between two devices, meaning that you have already gone through the advertising process governed by GAP.

        A BLE peripheral can only be connected to one central device (a mobile phone, etc.) at a time! As soon as a peripheral connects to a central device, it will stop advertising itself and other devices will no longer be able to see it or connect to it until the existing connection is broken.

        GATT Transactions
        An important concept to understand with GATT is the server/client relationship.

        The peripheral is known as the GATT Server, which holds the ATT lookup data and service and characteristic definitions, and the GATT Client (the phone/tablet), which sends requests to this server.

        All transactions are started by the master device, the GATT Client, which receives a response from the slave device, the GATT Server.

        When establishing a connection, the peripheral will suggest a 'Connection Interval' to the central device, and the central device will try to reconnect every connection interval to see if any new data is available, etc. It's important to keep in mind that this connection interval is really just a suggestion, though! Your central device may not be able to honor the request because it's busy talking to another peripheral or the required system resources just aren't available.

        Services and Characteristics
        GATT transactions in BLE are based on high-level, nested objects called Profiles, Services and Characteristics.
        alt text

        Profiles
        A Profile doesn't actually exist on the BLE peripheral itself, it's simply a pre-defined collection of Services that has been compiled by either the Bluetooth SIG or by the peripheral designers. The Heart Rate Profile, for example, combines the Heart Rate Service and the Device Information Service. The complete list of officially adopted GATT-based profiles can be seen here: Profiles Overview.

        Services
        Services are used to break data up into logic entities and contain specific chunks of data called characteristics. A service can have one or more characteristics, and each service distinguishes itself from other services by means of a unique numeric ID called a UUID, which can be either 16-bit (for officially adopted BLE Services) or 128-bit (for custom services).

        Characteristics
        The lowest level concept in GATT transactions is the Characteristic, which encapsulates a single data point (though it may contain an array of related data, such as X/Y/Z values from a 3-axis accelerometer, etc.).

        conclusion: we can see that it was a little bit different from Bluetooth classic that we used before, and now you can use the service and Characteristics to communicate with the BLE devices, also there is example code provided with esp32 board manager.

        • BLE Server example
        #define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
        #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
        
        • BLE Client example
        // The remote service we wish to connect to.
        static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
        // The characteristic of the remote service we are interested in.
        static BLEUUID    charUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8");
        

        Here we are defining the SERVICE_UUID and CHARACTERISTIC_UUID in the Server device then we are connecting from the Client device using the same SERVICE_UUID and CHARACTERISTIC_UUID .

        Resources :

        • Bluetooth Core Specification

        • Bluetooth Developer Portal

        • Officially Adopted BLE Profiles and Services

        • Officially Adopted BLE Characteristics

        • Introduction to Bluetooth Low Energy by Adafruit

        • https://github.com/nkolban/ESP32_BLE_Arduino

        kowshik1729 1 Reply Last reply Reply Quote 0
        • kowshik1729
          kowshik1729 @salmanfaris last edited by kowshik1729

          @salmanfaris
          Hello Salman...Thankyou very much for the reply. I implemented your code and I got below error. doubt.PNG

          I simply tried to read the temperature data from ESP32 and send it to the client ESP32 whenever it is connected. What is my error? Please help me out..!!

          salmanfaris 1 Reply Last reply Reply Quote 0
          • salmanfaris
            salmanfaris @kowshik1729 last edited by salmanfaris

            @kowshik1729 Could please share the full error log? (on the bottom right corner click copy error message) ,

            kowshik1729 1 Reply Last reply Reply Quote 0
            • kowshik1729
              kowshik1729 @salmanfaris last edited by

              @salmanfaris

              The complete error statement is the same as shown in the above image. Nothing else is printed in the Error Log.

              salmanfaris 1 Reply Last reply Reply Quote 0
              • salmanfaris
                salmanfaris @kowshik1729 last edited by salmanfaris

                @kowshik1729 Ok, then could you please share the central and peripheral code? can't find anything from the error instead of the missing function!

                kowshik1729 1 Reply Last reply Reply Quote 0
                • kowshik1729
                  kowshik1729 @salmanfaris last edited by

                  @salmanfaris
                  Sure...Here are my the codes that I have used.

                  kowshik1729 1 Reply Last reply Reply Quote 0
                  • kowshik1729
                    kowshik1729 @kowshik1729 last edited by

                    @kowshik1729

                    //                                Server side code
                    /*
                      A connect hander associated with the server starts a background task that performs notification
                      every couple of seconds.
                    */
                    #include <BLEDevice.h>
                    #include <BLEServer.h>
                    #include <BLEUtils.h>
                    #include <BLE2902.h>
                    
                    
                    #ifdef __cplusplus
                    extern "C" {
                    #endif
                    uint8_t temprature_sens_read();
                    #ifdef __cplusplus
                    }
                    #endif
                    uint8_t temprature_sens_read();
                    
                    
                    
                    BLEServer* pServer = NULL;
                    BLECharacteristic* pCharacteristic = NULL;
                    bool deviceConnected = false;
                    bool oldDeviceConnected = false;
                    float mea = 0;
                    int LED13 = 5;   //  The on-board Arduion LED
                    
                    // https://www.uuidgenerator.net/
                    
                    #define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
                    #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
                    
                    
                    class MyServerCallbacks: public BLEServerCallbacks {
                       void onConnect(BLEServer* pServer) {
                         deviceConnected = true;
                       };
                    
                       void onDisconnect(BLEServer* pServer) {
                         deviceConnected = false;
                       }
                    };
                    
                    
                    
                    
                    void setup() {
                     Serial.begin(115200);
                    
                     // Create the BLE Device
                     BLEDevice::init("ESP32");
                    
                     // Create the BLE Server
                     pServer = BLEDevice::createServer();
                     pServer->setCallbacks(new MyServerCallbacks());
                    
                     // Create the BLE Service
                     BLEService *pService = pServer->createService(SERVICE_UUID);
                    
                     // Create a BLE Characteristic
                     pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ   |
                                         BLECharacteristic::PROPERTY_WRITE  |
                                         BLECharacteristic::PROPERTY_NOTIFY 
                                       );
                    
                     // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
                     // Create a BLE Descriptor
                     pCharacteristic->addDescriptor(new BLE2902());
                    
                     // Start the service
                     pService->start();
                    
                     // Start advertising
                     BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
                     pAdvertising->addServiceUUID(SERVICE_UUID);
                     pAdvertising->setScanResponse(false);
                     pAdvertising->setMinPreferred(0x0);  // set value to 0x00 to not advertise this parameter
                     BLEDevice::startAdvertising();
                     pinMode(LED13, OUTPUT);
                     Serial.println("Waiting a client connection to notify...");
                    
                    }
                    
                    void loop() {
                     // notify changed value
                      // Read the PulseSensor's value.
                     // Assign this value to the "Signal" variable.
                     if (deviceConnected) 
                     {
                       mea = (temprature_sens_read()-32)/1.8;
                       String send_Data = String(mea);
                       pCharacteristic->setValue(send_Data);
                       pCharacteristic->notify();
                       
                       // bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms
                     }
                     else 
                     {
                       digitalWrite(LED13, LOW);               //  Else, the sigal must be below "550", so "turn-off" this LED.
                     }
                    
                     delay(10);
                    
                    }
                    

                    The following code is for the Client side.

                    //                                             Client Side code
                    
                    #include "BLEDevice.h"
                    #include "BLEScan.h"
                    
                    // The remote service we wish to connect to.
                    static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
                    // The characteristic of the remote service we are interested in.
                    static BLEUUID    charUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8");
                    
                    static boolean doConnect = false;
                    static boolean connected = false;
                    static boolean doScan = false;
                    static BLERemoteCharacteristic* pRemoteCharacteristic;
                    static BLEAdvertisedDevice* myDevice;
                    
                    static void notifyCallback(
                      BLERemoteCharacteristic* pBLERemoteCharacteristic,
                      uint8_t* pData,
                      size_t length,
                      bool isNotify) {
                      Serial.print("Notify callback for characteristic ");
                      Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
                      Serial.print(" of data length ");
                      Serial.println(length);
                      Serial.print("data: ");
                      Serial.println((char*)pData);
                    }
                    
                    class MyClientCallback : public BLEClientCallbacks {
                      void onConnect(BLEClient* pclient) {
                      }
                    
                      void onDisconnect(BLEClient* pclient) {
                        connected = false;
                        Serial.println("onDisconnect");
                      }
                    };
                    
                    bool connectToServer() {
                        Serial.print("Forming a connection to ");
                        Serial.println(myDevice->getAddress().toString().c_str());
                        
                        BLEClient*  pClient  = BLEDevice::createClient();
                        Serial.println(" - Created client");
                    
                        pClient->setClientCallbacks(new MyClientCallback());
                    
                        // Connect to the remove BLE Server.
                        pClient->connect(myDevice);  // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
                        Serial.println(" - Connected to server");
                    
                        // Obtain a reference to the service we are after in the remote BLE server.
                        BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
                        if (pRemoteService == nullptr) {
                          Serial.print("Failed to find our service UUID: ");
                          Serial.println(serviceUUID.toString().c_str());
                          pClient->disconnect();
                          return false;
                        }
                        Serial.println(" - Found our service");
                    
                    
                        // Obtain a reference to the characteristic in the service of the remote BLE server.
                        pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
                        if (pRemoteCharacteristic == nullptr) {
                          Serial.print("Failed to find our characteristic UUID: ");
                          Serial.println(charUUID.toString().c_str());
                          pClient->disconnect();
                          return false;
                        }
                        Serial.println(" - Found our characteristic");
                    
                        // Read the value of the characteristic.
                        if(pRemoteCharacteristic->canRead()) {
                          std::string value = pRemoteCharacteristic->readValue();
                          Serial.print("The characteristic value was: ");
                          Serial.println(value.c_str());
                        }
                    
                        if(pRemoteCharacteristic->canNotify())
                          pRemoteCharacteristic->registerForNotify(notifyCallback);
                    
                        connected = true;
                    }
                    /**
                     * Scan for BLE servers and find the first one that advertises the service we are looking for.
                     */
                    class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
                     /**
                       * Called for each advertising BLE server.
                       */
                      void onResult(BLEAdvertisedDevice advertisedDevice) {
                        Serial.print("BLE Advertised Device found: ");
                        Serial.println(advertisedDevice.toString().c_str());
                    
                        // We have found a device, let us now see if it contains the service we are looking for.
                        if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) {
                    
                          BLEDevice::getScan()->stop();
                          myDevice = new BLEAdvertisedDevice(advertisedDevice);
                          doConnect = true;
                          doScan = true;
                    
                        } // Found our server
                      } // onResult
                    }; // MyAdvertisedDeviceCallbacks
                    
                    
                    void setup() {
                      Serial.begin(115200);
                      Serial.println("Starting Arduino BLE Client application...");
                      BLEDevice::init("");
                    
                      // Retrieve a Scanner and set the callback we want to use to be informed when we
                      // have detected a new device.  Specify that we want active scanning and start the
                      // scan to run for 5 seconds.
                      BLEScan* pBLEScan = BLEDevice::getScan();
                      pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
                      pBLEScan->setInterval(1349);
                      pBLEScan->setWindow(449);
                      pBLEScan->setActiveScan(true);
                      pBLEScan->start(5, false);
                    } // End of setup.
                    
                    
                    // This is the Arduino main loop function.
                    void loop() {
                    
                      // If the flag "doConnect" is true then we have scanned for and found the desired
                      // BLE Server with which we wish to connect.  Now we connect to it.  Once we are 
                      // connected we set the connected flag to be true.
                      if (doConnect == true) {
                        if (connectToServer()) {
                          Serial.println("We are now connected to the BLE Server.");
                        } else {
                          Serial.println("We have failed to connect to the server; there is nothin more we will do.");
                        }
                        doConnect = false;
                      }
                    
                      delay(1000); // Delay a second between loops.
                    } // End of loop
                    
                    salmanfaris 1 Reply Last reply Reply Quote 0
                    • salmanfaris
                      salmanfaris @kowshik1729 last edited by salmanfaris

                      @kowshik1729 You are trying to pass a string value (send_Data) to a pointer object(setValue), to solve that you should use std::string class which is an instantiation of the basic_string class template that uses char (i.e., bytes) as its character type.

                      Comment line no.96 which doing convertion from Float value into String using the String constructor

                      // String send_Data = String(mea);
                      

                      and add the following line to use the std:string this will help represent the sequence of characters as an object of the class .

                      std::string send_Data((char*)&mea, 2);
                      

                      edited code

                      //                                Server side code
                      /*
                        A connect hander associated with the server starts a background task that performs notification
                        every couple of seconds.
                      */
                      #include <BLEDevice.h>
                      #include <BLEServer.h>
                      #include <BLEUtils.h>
                      #include <BLE2902.h>
                      #include <BLECharacteristic.h>
                      
                      
                      #ifdef __cplusplus
                      extern "C" {
                      #endif
                      uint8_t temprature_sens_read();
                      #ifdef __cplusplus
                      }
                      #endif
                      uint8_t temprature_sens_read();
                      
                      
                      
                      BLEServer* pServer = NULL;
                      BLECharacteristic* pCharacteristic = NULL;
                      bool deviceConnected = false;
                      bool oldDeviceConnected = false;
                      float mea = 0;
                      int LED13 = 5;   //  The on-board Arduion LED
                      
                      // https://www.uuidgenerator.net/
                      
                      #define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
                      #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
                      
                      
                      class MyServerCallbacks: public BLEServerCallbacks {
                         void onConnect(BLEServer* pServer) {
                           deviceConnected = true;
                         };
                      
                         void onDisconnect(BLEServer* pServer) {
                           deviceConnected = false;
                         }
                      };
                      
                      
                      
                      
                      void setup() {
                       Serial.begin(115200);
                      
                       // Create the BLE Device
                       BLEDevice::init("ESP32");
                      
                       // Create the BLE Server
                       pServer = BLEDevice::createServer();
                       pServer->setCallbacks(new MyServerCallbacks());
                      
                       // Create the BLE Service
                       BLEService *pService = pServer->createService(SERVICE_UUID);
                      
                       // Create a BLE Characteristic
                       pCharacteristic = pService->createCharacteristic(
                                           CHARACTERISTIC_UUID,
                                           BLECharacteristic::PROPERTY_READ   |
                                           BLECharacteristic::PROPERTY_WRITE  |
                                           BLECharacteristic::PROPERTY_NOTIFY 
                                         );
                      
                       // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
                       // Create a BLE Descriptor
                       pCharacteristic->addDescriptor(new BLE2902());
                      
                       // Start the service
                       pService->start();
                      
                       // Start advertising
                       BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
                       pAdvertising->addServiceUUID(SERVICE_UUID);
                       pAdvertising->setScanResponse(false);
                       pAdvertising->setMinPreferred(0x0);  // set value to 0x00 to not advertise this parameter
                       BLEDevice::startAdvertising();
                       pinMode(LED13, OUTPUT);
                       Serial.println("Waiting a client connection to notify...");
                      
                      }
                      
                      void loop() {
                       // notify changed value
                        // Read the PulseSensor's value.
                       // Assign this value to the "Signal" variable.
                       if (deviceConnected) 
                       {
                         mea = (temprature_sens_read()-32)/1.8;
                        // String send_Data = String(mea);
                         std::string send_Data((char*)&mea, 2);
                         pCharacteristic->setValue(send_Data);
                         pCharacteristic->notify();
                         
                         // bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms
                       }
                       else 
                       {
                         digitalWrite(LED13, LOW);               //  Else, the sigal must be below "550", so "turn-off" this LED.
                       }
                      
                       delay(10);
                      
                      }
                      

                      Try it out.

                      1 Reply Last reply Reply Quote 0
                      • kowshik1729
                        kowshik1729 last edited by kowshik1729

                        @salmanfaris Thanks for correcting me back. I implemented this on my ESP's and the data that I acquired on the client end is very weird as shown in the below image and whereas my client-side code remained the same as shown in the previous post.

                        doubt.PNG

                        salmanfaris 1 Reply Last reply Reply Quote 0
                        • First post
                          Last post

                        Recent Posts

                        • @codelery Awesome. That's great news. Kudos to @rafitc99 . 🙌

                          @codelery Please keep us updated about your project, looking forward to seeing it in action 🤩

                          • read more
                        • C

                          @rafitc99 I changed the buffer and that solved the problem. Thanks a lot for coming to my rescue.

                          • read more
                        • C

                          @salmanfaris I did change the buffer size and everything is working perfectly. Thanks coming to my rescue.

                          • read more
                        • @codelery said in Help needed: Arduino Wireless Notice Board project:

                          I am using the hardware serial (pin 0 and 1 on Arduino Uno)

                          As @rafitc99 mentioned, you need to expand the Serila buffer, in the hardware serial also the Arduino board package implements a 64-byte ring buffer for send and receive on the hardware serial messages. So you need to change that to 256 as per your message length.

                          • read more
                        • C

                          @rafitc99 The thing is that I am not using the SoftwareSerial library in receiving the message from the first microcontroller. I am using the hardware serial (pin 0 and 1 on Arduino Uno)

                          • read more
                        By MakerGram | A XiStart Initiative | Built with ♥ NodeBB
                        Copyright © 2023 MakerGram, All rights reserved.
                        Privacy Policy | Terms & Conditions | Disclaimer | Code of Conduct