This second part of the guide (here is the first part) ideally should have the working code matching with the title! But, ESP32 with Arduino IDE is not completely bug-free with BLE. So, instead of directly going to the topic, it will be practical for us to show some basic example codes which the readers can test on their setup. Not all of the readers can be expected to be used with BLE of ESP32 with Arduino IDE.
When you launch the Arduino IDE, probably you do not see the official examples for ESP32 (from Files > Examples). To view the examples, you need to go to Tools > Boards and select ESP32 Dev board as your board. There is a simple example of BLE :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #include "SimpleBLE.h" #if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED) #error Bluetooth is not enabled! Please run `make menuconfig` to and enable it #endif SimpleBLE ble; void onButton(){ String out = "BLE32 name: "; out += String(millis() / 1000); Serial.println(out); ble.begin(out); } void setup() { Serial.begin(115200); Serial.setDebugOutput(true); pinMode(0, INPUT_PULLUP); Serial.print("ESP32 SDK: "); Serial.println(ESP.getSdkVersion()); ble.begin("ESP32 SimpleBLE"); Serial.println("Press the button to change the device's name"); } void loop() { static uint8_t lastPinState = 1; uint8_t pinState = digitalRead(0); if(!pinState && lastPinState){ onButton(); } lastPinState = pinState; while(Serial.available()) Serial.write(Serial.read()); } |
It includes the header file SimpleBLE.h
and this code almost always correctly compile. So, this code is good to test your ESP32 from hardware point of view. Another example is of BLE client :
---
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | #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; } // If we are connected to a peer BLE Server, update the characteristic each time we are reached // with the current time since boot. if (connected) { String newValue = "Time since boot: " + String(millis()/1000); Serial.println("Setting new characteristic value to \"" + newValue + "\""); // Set the characteristic's value to be the array of bytes that is actually a string. pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length()); }else if(doScan){ BLEDevice::getScan()->start(0); // this is just example to start scan after disconnect, most likely there is better way to do it in arduino } delay(1000); // Delay a second between loops. } // End of loop |
The above code is most important for our project. Check whether it compiles correctly. It is not rare to face an error with BLEDevice.h
. If it gets properly compiled and get uploaded then you do not have many difficulties ahead. We will start our code in the same way as the above example. We can start this way :
1 2 3 4 5 | #include "BLEDevice.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"); |
How our ESP32 will understand that our watch is closer? It has to respond to known the MAC address of the watch. We got the MAC address using the Android app described in the first part of this article. Unless we know the MAC address, for Bluetooth outside the Discoverable Mode, it is not possible to match. You need to read some basic theory.
Similar idea for Wi-Fi is a good project :
1 | https://github.com/skickar/FriendDetector |
WLAN probe request and probe request frame are defined in IEEE standard. As the idea can take massive open spying, there are minimum securities at software and hardware layers! That makes the coding part slightly difficult. Click here to read the third part of this series.