nkolban / esp32-snippets

Sample ESP32 snippets and code fragments
https://leanpub.com/kolban-ESP32
Apache License 2.0
2.35k stars 710 forks source link

Accessing additional service uuid after connecting #614

Closed kirawadden closed 6 years ago

kirawadden commented 6 years ago

I'm working on a project that requires writing to a characteristic UUID in order to access data from the device's other service UUIDs. I need to be able to access an additional service UUID after connecting to the primary service UUID and writing to the primary characteristic. This is possible on nrf connect, but is it possible using this library?

chegewara commented 6 years ago

Sorry, but at the moment service is hardcoded as primary service. If you would have some example code that i can work with that would help me to change library to work with included services or you can try to change library: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/BLEService.cpp#L75

kirawadden commented 6 years ago

I should clarify my question; I am using my esp32 as a client, and the server I am trying to connect to requires writing a command to a characteristic, in order to receive notifications from another characteristic. Is it possible to connect to the additional characteristic after the command is written to the initial characteristic?

chegewara commented 6 years ago

Its something new to me and its hard to advise something, maybe i will have better image seeing how characteristics and services are dependent. Could you connect with nRF connect android application to this peripheral and take screenshot with services and characteristics you want to read/write?

kirawadden commented 6 years ago

I'm working a device called the Myo Armband, this is how it appears on the scanner: on_scanner When we connect, we get a few different services: img_7634 And a few more services if we scroll down - the service I am interested in is highlighted in the screenshot when I scroll down: emg_service If we tap on the highlighted service in the last picture, we get 4 different characteristics. These characteristics have the property notify, and it doesn't matter to me which one we use. The issue comes in here, if we just subscribe to notifications from one of these characteristics, we will get no data. emg_no_notifications As specified in the header file provided for the Myo Armband's ble protocol, we must go to the service d5060001-a904-deb9-4748-2c7f4a124842 (control service), and write to the command characteristic (d5060401-a904-deb9-4748-2c7f4a124842). After a lot of trial and error, I have determined that the command I want to write is 0x0103020001 - I can explain this command if it helps, but it's not super relevant to my issue. The command basically asks the device to set the mode, and asks the service I am interested in, d5060005-a904-deb9-4748-2c7f4a124842, to turn on notifications. Go to control service: control_service Select the command characteristic: write to control service Write to characteristic: write to command char After writing to this characteristic, we can go back to the service d5060005-a904-deb9-4748-2c7f4a124842, and subscribe to notifications. This time, we get values. In the screenshot, I unsubscribed to notifications because the values we coming in too quickly to screenshot. But, you can see that the value is no longer 0x0000000(...). emg_notifications So this is kind of a complicated process, and I am not sure if it would be possible with the esp ble library, but it would super useful it was! Thank you for your help, I hope the screen shots clarify my question.

chegewara commented 6 years ago

Few characteristics like D506105, D506205 and D506305 have set preporties as NOTIFY. Now what you have to do is to register for notify for characteristics you are interested to receive notifications. Im guessing when you write some value to characteristic with WRITE properties then your device is performing some action and sending notification on different characteristic. Here is example how to do it: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLETests/SampleClient_Notify.cpp or arduino: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLETests/Arduino/BLE_client/BLE_client.ino

kirawadden commented 6 years ago

Sorry, would it be possible to highlight which lines you are referring to in those sketches? Also, I know that the D506105, D506205, and D506305 have the descriptor 0x2902, however, I don't think you can write to that descriptor to turn on notifications. This is because when you write the command to characteristic D5060401, you specify what type of data you would like (the characteristics 0x0105, 0x0205, 0x0305 send emg data, and in the written command I specify if I want the data to stream filtered, or unfiltered). This is the header file I am working off of for the Myo Armband's ble protocol if you are interested in looking at it: https://github.com/thalmiclabs/myo-bluetooth/blob/master/myohw.h

chegewara commented 6 years ago

This is code you are interested in and you have to write it for each characteristic you want to receive notifications (just insert characteristics UUID from your device): https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLETests/SampleClient_Notify.cpp#L50-L68 Here you will receive notifications: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLETests/SampleClient_Notify.cpp#L28-L35 You can have one callback for all notifications or separate callback for each characteristic.

PS you have to use full UUID value (16 bytes)

kirawadden commented 6 years ago

Yes, not using the full UUID was my original mistake 😅 Is it possible to use the arduino esp sketches for this, or should I use the C++ sketches you sent?

chegewara commented 6 years ago

Yes, you can use arduino-ide, but you have to copy/paste those 2 files to get it easier to register for notifications: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/BLERemoteCharacteristic.cpp https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/BLERemoteCharacteristic.h

kirawadden commented 6 years ago

Copy paste these into the arduino client sketch?

chegewara commented 6 years ago

You have to find this folder (assuming you are using windows) and replace files: Documents\Arduino\hardware\espressif\esp32\libraries\BLE\src

kirawadden commented 6 years ago
screen shot 2018-07-31 at 8 38 11 pm

Is this correct? (I'm using a Mac)

chegewara commented 6 years ago

yes

kirawadden commented 6 years ago

Hello, I'm sorry I've been away so long haven't had time to work on this project. I've gotten my client to connect to desired characteristic and service uuids, but I am unsure that the notifyCallback function is working. This is how I am connecting to the additional service and characteristic uuids (emgSUUID is the additional service I want, and emgCUUID is the additional characteristic I want):

pRemoteService = pClient->getService(emgSUUID); if (pRemoteService == nullptr) { Serial.print("Failed to find our service UUID: "); Serial.println(emgSUUID.toString().c_str()); return false; } Serial.println(" - Found our EMG service"); Serial.println(emgSUUID.toString().c_str()); // Obtain a reference to the characteristic in the service of the remote BLE server. pRemoteCharacteristic = pRemoteService->getCharacteristic(emgCUUID); if (pRemoteCharacteristic == nullptr) { Serial.print("Failed to find our characteristic UUID: "); Serial.println(emgCUUID.toString().c_str()); return false; } Serial.println(" - Found our EMG characteristic"); Serial.println(emgCUUID.toString().c_str()); //std::string value = pRemoteCharacteristic->readValue(); pRemoteCharacteristic->registerForNotify(notifyCallback); and this is what is printing to my serial monitor:

screen shot 2018-08-10 at 10 44 03 am

So I'm not sure that notifyCallback is working since the Serial.println statements that are in the function aren't showing up on the serial monitor. From there, I was also wondering how I might be able to print the notifications from the characteristic to the serial monitor. I know that notifications will come in without requesting them from the server, so I was wondering if there is a function we need to call to see the updated notification value, or if this would happen automatically.

chegewara commented 6 years ago

Its few possibilities. If you have original arduino-ble library then there is missing few lines of code in examples that will allow you to receive notifications. Its all described in few issue posts in this repo. Because its very confused i did change in this library that will allow to register for notifications without extra code. Thats why i asked you to copy/paste those files.

Now, even if you have properly registered for notifications its possible that peer device is not sending any notifications yet. If i remember you should get notification when you send value to characteristic. Maybe you need to send special value, not "Time since boot: "?

kirawadden commented 6 years ago

I am currently writing to characteristic 0x0401: const uint8_t writeVal[] = {0x0103020001}; pRemoteCharacteristic->writeValue((uint8_t*)writeVal, 1, true); and this is followed by the code in my last comment. In the void loop(), this is all that is happening: 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()); } so I am not currently writing anything to the characteristic 0x0105. If we are getting notifications, is there a way to print them to the serial monitor?

chegewara commented 6 years ago

Here: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLETests/Arduino/BLE_client/BLE_client.ino#L18-L27

kirawadden commented 6 years ago

Thank you for all of your help! I realized I was writing the value wrong to the characteristic which is why the notification didn't work.