How Can Peripheral Get Notification on Central Bond Delete - bluetooth-lowenergy

Peripheral: Nordic nRF52840 chipset with Zephyr
Central: Android smartphone
Bond is created and "pairing_complete" callback is called in peripheral.
But when manually delete the bonding(from Bluetooth > [peripheral device]Unpair), how can the peripheral gets a notification?
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
};
struct bt_conn_auth_cb cb = {
.cancel = cancel,
.oob_data_request = NULL,
.pairing_confirm = NULL,
.passkey_confirm = pass_confirm,
.passkey_display = pass_display,
.passkey_entry = NULL,
};
bt_conn_auth_cb_register(&cb);
struct bt_conn_auth_info_cb info_cb = {
.bond_deleted = bond_deleted, // ------> not getting called when central deletes the pairing
.pairing_complete = pairing_complete,
.pairing_failed = pairing_failed,
};
bt_conn_auth_info_cb_register(&info_cb);
The callbacks are implemented as usual.
My question is, when user deletes the bonding(unpair) from smartphone:
Why the peripheral not getting notification in "bond_deleted' callback?
Is there any other way to get this notification?
Or is this BLE concept?
FYI:
"disconnected" callback is getting called
After disconnection, if I connect from another central, peripheral gets the "bond_deleted" called before bonded

The bond_deleted callback seems only being called when the bond removal is initiated by the local device, as seen here: https://github.com/zephyrproject-rtos/zephyr/pull/26876 where it was introduced. Maybe this callback is called for you when you bond a new central because the oldest one is being removed.
Naturally, the peripheral can't be notified of the bond removal in the central in case the peripheral is disconnected (e.g. out of range) when being unbonded in the central.
If there is a connection ongoing while the central unbonds, then unfortunately it just disconnects without informing the peripheral that the central has removed its bond. The next time it connects (if it ever does so), it will need to perform a new pairing attempt in case it needs to communicate securely.
To solve the issue that the peripheral is not notified of the unbonding attempt, there is a BLE service for that: the Bond Management Service. See https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/samples/bluetooth/peripheral_bms/README.html for an nRF Connect SDK implementation. I'm not sure if Android implements it though (I would be surprised if it did).

Related

How to enable notification and indications on Arduino nano 33 IOT BLE descriptor?

I am making BLE echo system between Arduino and Android.
I have finished to make read and write function. But I want Android can automatically detect value when BluetoothGattCharacteristic value change. So I made set notification on Android.
When I tried to check the fucntion is working properly or not, It was not working properly. And I use nRFConnect App to check what is the problem. the problem is the status of descriptor on Arduino is Notification and indications disabled. And I googled how to enable notification and indication on Arduino. But on the Arduino's document, I cannot find the function which can make enable descriptor's notification and indication. this is the document link. So is it possible to enable notification and indication on Arduino BLE??
Code of Arduino nano 33 IOT.
#include <ArduinoBLE.h>
BLEService echoService("00000000-0000-1000-8000-00805f9b34fb");
BLEStringCharacteristic charac ("741c12b9-e13c-4992-8a5e-fce46dec0bff", BLERead | BLEWrite | BLENotify,40);
BLEDescriptor Descriptor("beca6057-955c-4f8a-e1e3-56a1633f04b1","Descriptor");
String var = "";
void setup(){
Serial.begin(9600);
while(!Serial);
if(!BLE.begin()){
Serial.println("starting BLE failed.");
while(1);
}
BLE.setLocalName("Arduino BLE Echo");
BLE.setAdvertisedService(echoService);
charac.addDescriptor(Descriptor);
echoService.addCharacteristic(charac);
BLE.addService(echoService);
BLE.advertise();
Serial.println("Bluetooth device active, waiting for connections...");
Serial.println(" ");
}
void loop(){
BLEDevice central = BLE.central();
if(central){
Serial.println("* Connected to central device!");
Serial.print("Connected to central : ");
Serial.println(central.address());
Serial.println(" ");
while(central.connected()){
if(charac.written()){
var = charac.value();
Serial.println(String(var));
delay(500);
charac.writeValue(var);
Serial.println("write stringCharacteristic");
}
}
Serial.print("Disconnected from central: ");
Serial.println(central.address());
}
}
picture of nRFConnection APP.
You need to enable the notifications from the Android side in order to receive the BLE notifications. This is because according to the BLE specification, BLE notifications are disabled by default. If you want BLE notifications to remain enabled after the first time you enable them, you can bond with the Arduino device. This way, the status of the notification will persist across power cycles and disconnection/reconnection, and as soon as you reconnect to the Arduino device, notifications will be enabled by default (but again, you still have to enable them the first time).
This can be seen in the paragraph below (Bluetooth Specification v5.3, Vol 3, Part G, Section 3.3.3.3 - Clinet Characteristic Configuration - Page 1489):-
"The Client Characteristic Configuration declaration is an optional
characteristic descriptor that defines how the characteristic may be
configured by a specific client. The Client Characteristic
Configuration descriptor value shall be persistent across connections
for bonded devices. The Client Characteristic Configuration descriptor
value shall be set to the default value at each connection with
non-bonded devices.The characteristic descriptor value is a bit
field. When a bit is set, that action shall be enabled, otherwise it
will not be used. The Client Characteristic Configuration descriptor
may occur in any position within the characteristic definition after
the Characteristic Value. Only one Client Characteristic Configuration
declaration shall exist in a characteristic definition.
The default value for the Client Characteristic Configuration descriptor value shall be 0x0000."
Note that the Client Characteristic Descriptor (CCCD) is the attribute in the characteristic that handles notification/indications. You can read more about this here:-
Bluetooth Low Energy: A Primer
Bluetooth GATT
Bluetooth Low Energy Characteristics Tutorial

How comunicate with UART Transparent service BLE in xamarin

I'm trying to do an app with xamarin which can communicate with a chip rn4870. This BLE chip uses UART Transparent services. I'm new with bluetooth, so the most thing I read for do a communication with a ble device is to scan the device, connect it, looking for the service you want, get the characteristics and write,read or notify.
But, The most example I read, with heart rate device o smarthwath, the service is defined , for example a service for a battery, so, I can get the service, then the characteristic and read it. But with UART Transparent service, I get the 49535343-FE7D-4AE5-8FA9-9FAFD205E455 service to datatransfer, and then I get TX 49535343-1E4D-4BD9-BA61-23C647249616 and RX 49535343-8841-43F4-A8D4-ECBE34729BB3 characteristic but I don't know how to communicate.
Also I'm using plugin BLE of xamarin, with these plugin I can not see any particular function or documentation where I can use client/server functionality.
https://github.com/xabre/xamarin-bluetooth-le
So, if anyone has a idea how or which step I have to follow to can communicate with it and if you know how I could do it with xamarin, I will appreciate.
Thanks in advance.
You can handle the UART transparent service the same way you would handle a battery service.
Scan for available devices, even better if you use a filter to only find devices offering the UART service
adapter.DeviceDiscovered += (s,a) => deviceList.Add(a.Device);
await adapter.StartScanningForDevicesAsync(new[] { Guid.Parse("49535343-FE7D-4AE5-8FA9-9FAFD205E455"));
Connect to the device
try
{
await _adapter.ConnectToDeviceAsync(device);
}
catch(DeviceConnectionException e)
{
// ... could not connect to device
}
Get the UART service and both of the characteristics
var TX = await connectedDevice.GetServiceAsync(Guid.Parse("49535343-1E4D-4BD9-BA61-23C647249616"));
var RX = await connectedDevice.GetServiceAsync(Guid.Parse("49535343-8841-43F4-A8D4-ECBE34729BB3"));
Enable notifications on the TX characteristic to receive the answers and start writing to the RX characteristic
TX.ValueUpdated += (o, args) =>
{
// Do something with the received value
var bytes = args.Characteristic.Value;
};
await TX.StartUpdatesAsync();
await RX.WriteAsync(bytes);
If you want to test the connection and the communication procedure you can use a generic BLE scanner app such as nRF Connect. Use it to search for your device and you can read, write and activate notifications with it.
There is also a sample app using your xamarin plugin that offers this functionality:
check the ble status
discover devices
connect/disconnect
discover the services
discover the characteristics
see characteristic details
read/write and register for notifications of a characteristic

How to handle the device watcher "cache" of old devices on start-up?

I have one BLE application.
When I start the device scanning, the DeviceWatcher.Added event will call immediately and shows the previously connected devices which is currently powered off. But in the DeviceWatcher.Removed event it will be cleared.
How can I prevent this situation. In my application I am trying to connect the device immediately when ever there is the device listed in the DeviceWatcher.Added event. I don't want to wait till the DeviceWatcher.EnumerationCompleted event.
Because of this implementation, the connection API BluetoothLEDevice bluetoothLEDevice = BluetoothLEDevice::FromIdAsync(GetId()).get(); is returning success. And in the service scan API GattDeviceServicesResult result = m_BluetoothLEDevice.GetGattServicesAsync(BluetoothCacheMode::Uncached).get(); I am getting GattCommunicationStatus::Unreachable status.
I need this status in the initial time of scanning. Or there is any other way I can check the device is unreachable or not?
The sample written here is in C#, you could find the C++ replacement in the learn.microsoft.com
You could get all the paired BLE devices like this.
var pairedBleDevices = await DeviceInformation.FindAllAsync(BluetoothLEDevice.GetDeviceSelectorFromPairingState(true)); # Return all the paired Bluetooth LE devices
Now, if you want to remove the pairing of a specific device, you could loop through the pairedBleDevices and find your removal device by matching specific property, let's say device name or address.
foreach (var device in pairedBleDevices )
{
if (!device::Name.Contains("myDevice")) continue;
await device.Pairing.UnpairAsync();
break;
}
Now, as you have all the previously paired LE devices with properties, as Mike suggested, you could use BluetoothLEAdvertisementWatcher to discover BLE devices and filter the advertisement by matching the BluetoothAddress(from the paired device). If you find a new device, pair the device or execute the GATT operation and start communicating.
You are getting GattCommunicationStatus::Unreachable that's probably the device you are trying to communicate with is in sleep mode. So the best way is to capture the advertisement first using BluetoothLEAdvertisementWatcher and, after that, initiate the pairing or GATT operation.

Bluez BLE Connections Monitoring using DBUS-Python

I was able to advertise the BLE and setup GATT Services and Characteristics by following the "example_advertisement" and "example-gatt-server" in Bluez Examples. How can I know from DBUS when a BLE client is connected and when it is disconnected, using similar DBUS binding for Python? Which DBUS API do I look into?
There is another example that you can look at: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/test/test-discovery
When BlueZ/DBus learns of a new remote device, then the InterfacesAdded signal gets sent.
When a remote device goes from disconnected, to connected. Then that is a property change on the device and the PropertiesChanged signal gets sent.
This is why there is the code in the above example they use add_signal_receiver to add callbacks for both signals.
bus.add_signal_receiver(interfaces_added,
dbus_interface = "org.freedesktop.DBus.ObjectManager",
signal_name = "InterfacesAdded")
bus.add_signal_receiver(properties_changed,
dbus_interface = "org.freedesktop.DBus.Properties",
signal_name = "PropertiesChanged",
arg0 = "org.bluez.Device1",
path_keyword = "path")
As a side note, the DBus bindings used in the Buez examples are not the only ones available:
https://www.freedesktop.org/wiki/Software/DBusBindings/

Android BLE API: Autoconnect does not work for every device?

I have two peripheral devices, say device1 & device2 and one Android device for central role. Android can connect to both by BluetoothDevice.connectGatt() method with autoConnect = false.
Problem is - While autoConnect functionalities work well for device1, device2 even does not connect for once with autoConnect = true.
onConnectionStateChange callback is not called in either side (android & device2).
Advertisement and scan-response packets been customized in device2, is that causing the problem? Though we know that, settings for autonomous connection is to be provided entirely at central side, peripheral side has nothing to do with it, change in peripheral device also changing auto-connect behavior at central side.
any insight? Thanks in advance.

Resources