Open SensorsIot opened 6 years ago
Hi, one question, are you using library from https://github.com/nkolban/ESP32_BLE_Arduino or from https://github.com/nkolban/esp32-snippets. In other words, in arduino ide are installing library from zip file or from library manager?
From the original distribution (with git clone)
Original distribution is https://github.com/nkolban/esp32-snippets
So there are differences between espressif/arduino-esp32 and https://github.com/nkolban/esp32-snippets? Which one do you suggest?
At the moment, until we dont get support c++ exceptions in arduino-esp32 i suggest to not change to esp32-snippets, and when we have c++ exceptions working in arduino-ide most likely library delivered with arduino-esp32, which you call original distribution, will be updated.
Back to your issue, i will investigate it and back to you soon. In mean time, can you turn on verbose logging in arduino-ide and provide more logs?
I switched it on and compiled the client file. Where should I post the log?
pastebin or here
It is here: https://pastebin.com/5299TxCV
Ok, ive found the problem. Those two examples are not prepared to work with each other without some changes. As you can see in this line https://github.com/nkolban/ESP32_BLE_Arduino/blob/f8fe9d7cdfb20caa54b70849826d1ac6e375ff78/examples/BLE_client/BLE_client.ino#L78
BLE_client expecting that server is advertising UUID, but BLE_notify example is not advertising any UUID. You can change it very easy by adding this line
pServer->getAdvertising()->addServiceUUID(BLEUUID(SERVICE_UUID));
somwhere in here https://github.com/nkolban/ESP32_BLE_Arduino/blob/f8fe9d7cdfb20caa54b70849826d1ac6e375ff78/examples/BLE_notify/BLE_notify.ino#L78
tis will let you to connect 2 esp32 by using BLE_client and BLE_notify examples. There is one more thing you have to remember. When you are advertising 128 bit UUID then name of device cant be longer than 5 characters.
You can also change this line https://github.com/nkolban/ESP32_BLE_Arduino/blob/f8fe9d7cdfb20caa54b70849826d1ac6e375ff78/examples/BLE_client/BLE_client.ino#L78 and search device you want to connect to not by advertised UUID but ie by name, or served service etc
Now it works. Very good! Thank you very much for your help. Now I can go on with my Polar H7 emulation... And with my new video where I need BLE UART functionality. So it is well possible that I have to come back because for the moment I can only transfer a few characters to my Smartphone... Just a small question concerning your additional line: Why do I have to use BLEUUID(SERVICE_UUID) and not only (SERVICE_UUID)?
You can use both, BLEUUID(SERVICE_UUID) and (SERVICE_UUID) because this method is overloaded and can be used with BLEUUID or with string uuid.
EDIT you can use both only in case if SERVICE_UUID is 128 bit uuid in string variable. In case you want to use 16 or 32 bit uuid only BLEUUID(SERVICE_UUID) works
I try now to read the values sent by notify. in BLE_notify I inserted: cscCharacteristic.setValue(csc, 11); cscCharacteristic.notify();
In BLE_client I am able to see the values once during connect of the characteristics: in connectToServer(BLEAddress pAddress) at the bottom I inserted: // Read the value of the characteristic. std::string value = pRemoteCharacteristic->readValue(); Serial.println("The characteristic value was: "); for (int i = 0; i < value.length(); i++) Serial.println(value[i], HEX); Serial.print("length: "); Serial.println(value.length());
But not during notifyCallback:
static void notifyCallback( BLERemoteCharacteristic pBLERemoteCharacteristic, uint8_t pData, size_t length, bool isNotify) { Serial.print("Notify callback for characteristic "); Serial.println(pBLERemoteCharacteristic->getUUID().toString().c_str());
Serial.println("The characteristic value was: "); // Read the value of the characteristic. std::string value = pBLERemoteCharacteristic->readValue(); for (int i = 0; i < value.length(); i++) Serial.println(value[i], HEX); Serial.print("length: "); Serial.println(value.length()); } The callback is called, but the line std::string value = pBLERemoteCharacteristic->readValue(); blocks the execution In NRFconnect the csc value counts up
The whole code is here (strongly based on the notify example) https://pastebin.com/PbtSvvVU
And the notifier: https://pastebin.com/0ngKNkef (based on the Cadence and speed service)
In my case with original BLE_notify and BLE_client i can receive notifications, but i will investigate custom code.
I see the problem. Here you have created chracteristic with notify:
BLECharacteristic cscCharacteristic(BLEUUID((uint16_t)0x2A5B), BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
thats good, but if you will check with nRF connect there is missing something. With properly implemented notify/indicate functionality you will see three arrows like on this picture http://a2.mzstatic.com/us/r30/Purple18/v4/21/65/4d/21654db0-6c4e-2237-18a5-624b22e783da/screen696x696.jpeg
This leads us to conclusion there is missing something. Every characteristic with notify and/or indicate needs to have descriptor 2902. There is special library which help to create and add this descriptor BLE2902.
Thank you for your help. Sorry for coming back late. I was away. Now my H7 fake works and delivers values to nRF connect. I can switch notifications on and off using BLE2902. Great. I again watched Neils videos and understood them now much more. The next problem I have is on the client side and unfortunately, Neil did not explain in his client video is how to display the notified values in the client. I get them once the client connects to the server and, if I put a pRemoteCharacteristic->readValue(); in the loop() I get also the updates. But not in a callback, which would be much nicer to avoid getting the same value twice... Also, I do not know how I can disable notifications from my ESP client (with the phone I just push the three arrows and the BLE2902 disables notifications). Is there a documentation of these commands? I looked into Neils ESP32 book but it is somehow a mixture between c and c++
No rush, we dont have timeline when you have to comeback and response.
Thats strange, you should have get notifications and read value in notificationCallback. See this code: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLETests/Arduino/BLE_client/BLE_client.ino#L18
If you asking about turning on/off notifications, you need to read remoteDescriptor BLE2902 descriptor from pRemoteCharacteristic and then writeValue(bool): https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/BLERemoteDescriptor.h#L36
pRemoteCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902)->writeValue(0) <- TURN OFF
pRemoteCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902)->writeValue(1) <- TURN ON NOTIFICATIONS ONLY
pRemoteCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902)->writeValue(2) <- TURN ON INDICATIONS ONLY
pRemoteCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902)->writeValue(3) <- TURN ON NOTIFICATIONS AND INDICATIONS
Interesting things happen:
Sorry for #1. I was stupid and did not understand the concept. Now it works.
Nothing wrong happened, im glad it works.
Sorry it takes so long, but honestly documentation on bluetooth.org sucks. This is the right solution to turn on notifications:
const uint8_t v[]={0x1,0x0};
pRemoteCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)v,2,false);
Explanation:
If something else requires explanation dont hesitate to ask.
I tried now your code and get the following response in the Server: E (516057) BT: GATTS_SendRsp conn_id: 3 waiting for op_code = 00 E (516057) BT: Sending response failed E (517077) BT: GATTS_SendRsp conn_id: 3 waiting for op_code = 00 E (517077) BT: Sending response failed The notifications do not stop
I put the statement in the loop after (connectToServer(*pServerAddress). If I put it at the end of init the esp crashes. Is there a particular place where it has to go? BTW what would then be the command to switch it on?
For comparision i will post my code. This is client code, which will switch on/off notifications:
/**
* A BLE client example that is rich in capabilities.
*/
#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 BLEAddress *pServerAddress;
static boolean doConnect = false;
static boolean connected = false;
static BLERemoteCharacteristic* pRemoteCharacteristic;
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);
}
bool connectToServer(BLEAddress pAddress) {
Serial.print("Forming a connection to ");
Serial.println(pAddress.toString().c_str());
BLEClient* pClient = BLEDevice::createClient();
Serial.println(" - Created client");
// Connect to the remove BLE Server.
pClient->connect(pAddress);
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());
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());
return false;
}
Serial.println(" - Found our characteristic");
// Read the value of the characteristic.
std::string value = pRemoteCharacteristic->readValue();
Serial.print("The characteristic value was: ");
Serial.println(value.c_str());
pRemoteCharacteristic->registerForNotify(notifyCallback);
delay(100);
}
/**
* 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 (1) { <-- THIS is not important in my case, i have just 1 device so i want to connect to first found device, but in normal case its required to search device by name, or advertised service or any other parameter
//
Serial.print("Found our device! address: ");
advertisedDevice.getScan()->stop();
pServerAddress = new BLEAddress(advertisedDevice.getAddress());
doConnect = 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 30 seconds.
BLEScan* pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true);
pBLEScan->start(1);
} // End of setup.
// This is the Arduino main loop function.
bool onoff = false;
const uint8_t x[]={0x0,0x0};
const uint8_t v[]={0x1,0x0};
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(*pServerAddress)) {
Serial.println("We are now connected to the BLE Server.");
connected = true;
} 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());
if (onoff) pRemoteCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)x, 2, true);
else pRemoteCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)v,2,true);
onoff=onoff?0:1;
}
delay(10000); // Delay a second between loops.
} // End of loop
Server code is BLE_notify
Great! Now it works here too. I still get these messages from the server.
E (311726) BT: GATTS_SendRsp conn_id: 3 waiting for op_code = 00 E (311726) BT: Sending response failed
But who cares if it works ;-) Thank you for your help. I learned a lot in the last two days. BTW: I was able to transfer messages with a length of 140 bytes. This is important for my next project. It seems, that this BLE is really cool stuff.
Yes, im getting those messages too. But they are from esp-idf stack and sometimes even if they are suggesting its error (E) it is for information purpose only.
PS thanks to you i learned some stuff too, especially about descriptors and switching remote notifications.
Thanks. They do not appear if I switch notification off from nRF. So it seems to be a difference between the ESP sketch and the nRF. Minor thing...
@chegewara I have the same problem in the BLE_uart.ino demo.
I added as you suggested the extra line (line 100):
pServer->getAdvertising()->addServiceUUID(BLEUUID(SERVICE_UUID));
But the serviceUUID seems not advertised as it should be (see screenshot):
I am using version 0.4.13 of the library:
When I connect manually, the UART service becomes available, but I can't scan on devices advertising this serviceUUID.
Is there anything I can do?
There is 2 options:
Thx. the first trick did the job! But I don't quite understand what you mean bij adding it to the scan advertising?
for the moment the advertising part are these lines:
// Start the service
pService->start();
// Start advertising
pServer->getAdvertising()->addServiceUUID(BLEUUID(SERVICE_UUID));
pServer->getAdvertising()->start();
Yes, but you have regular advertising packet and scan advertising packet, 31 bytes each.
Can you explain that to me with an example?
You can set two different set of advertising data: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/BLEAdvertising.cpp#L139-L166
I am trying to understand it, but this does not seem te work with a devicename > 5 characters:
// Start the service
pService->start();
// Start advertising
BLEAdvertising *pAdvertising;
pAdvertising = pServer->getAdvertising();
pAdvertising->addServiceUUID(BLEUUID(SERVICE_UUID));
BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
pAdvertising->setScanResponseData(oScanResponseData);
pAdvertising->start();
You need to leave with empty name BLEDevice::init("")
and set it here for scan response (oScanResponseData ):
https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/BLEAdvertising.h#L28
// Start advertising
BLEAdvertising *pAdvertising;
pAdvertising = pServer->getAdvertising();
pAdvertising->addServiceUUID(BLEUUID(SERVICE_UUID));
BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
oScanResponseData->setName("myUartDevice");
pAdvertising->setScanResponseData(oScanResponseData);
pAdvertising->start();
gives an error now: base operand of '->' has non-pointer type 'BLEAdvertisementData'
but in the documentation it should be?
BLE is driving me crazy ;)
I'm not working with Arduino, but with a mobile framework. When writing data I was also receiving the error E (982295) BT_GATT: GATTS_SendRsp conn_id: 3 waiting for op_code = 00
Upon writing to a characteristic, there are typically two options. WriteWithoutResponse or WriteWithRepsonse, make sure to WriteWithResponse to avoid any response errors on ESP.
I use the BLE_notify example without changes and try to connect to it using the BLE_Client example. The only changes I did there was to copy the two UUID strings of the notify example to the client example to be sure they match. NRF connect shows the service but BLE_Client does not show it and also does not connect. Output: BLE Advertised Device found: Name: MyESP32, Address: 24:0a:c4:12:ef:a2, txPower: -21 I had this issue with many other examples but I am pretty sure it worked last week. To be sure I also downloaded the newest ESP32 environment from GitHub, with no change I also have a Xiaomi Flower care device around: Output: BLE Advertised Device found: Name: Flower care, Address: c4:7c:8d:62:87:f7, serviceUUID: 0000fe95-0000-1000-8000-00805f9b34fb If I copy this UUID to the client sketch, it connects.