After discovering the nearby Bluetooth devices either using StartDiscovery without filter or with SetDiscovertFilter, next big step is to connect with the device and access the functionalities provided by the device. The connection process involves two steps,
- Pairing – Authenticating and trusting the end bluetooth device
- Connect itself
Here connection can be initiated either by the Bluetooth device or by the Bluetooth adapter itself on behalf of application. The Authentication mechanism involves accepting the device/adapter using PIN/confirmation key. We are not going in details about the Secure Simple Pairing (SSP) of Bluetooth here as bluetoothd hides all the details already. Bluez5 uses Agent style implementation of authentication in favor to the external application. To understand in details, lets assume the following use case,
- User wants to connect to the Car Infotainment System (IVI) using bluetooth and initiates the connection from the mobile device. In this case, IVI head unit displays the PIN/confirmation code based on its Agent configurations. Then the user enters the same PIN or confirm yes/no from the mobile device. In this use case,
- IVI wants to show up the confirmation/PIN in its own wizard or pop (e.g GTK)
- Mobile device wants to pop up confirmation/Input field in its wizard
In favor of such implementations, Bluez5 provide Agent style API’s i.e Bluetooth Application can register it’s capability (yes/no confirmation or PIN entry) and also it’s own wizard implementation with the bluetoothd. Whenever there is a new connection from a device, bluetoothd automatically takes care to callback the registered API (where wizard or user application is implemented).
From the flow diagram, you can see,
- UI application registers its capability with method callbacks with bluetoothd
- StartDiscovery for scanning new devices
- Pair with the device
- bluetoothd callsback the API in UI for PIN/confirmation about the authentication
- Based on the response, bluetoothd decides to proceed or not for pairing
- Followed by Connect call to the Device1 interface (we will explore this interface in detail in next few blogs)
To get started with connection and for the completeness of the API’s coverage in adapter-api.txt, we will first explore the “ConnectDevice” API introduced in Bluez 5.49. As of this blogging date, this API is marked experimental for testing (mostly stable). To explore the below example on ConnectDevice, one must run the bluetoothd service/daemon in experimental mode by passing “-E” as argument.
Code:
ConnectDevice: This API is introduced in favor of answering following questions,
When this API is useful?
- When you already have the MAC address of end bluetooth Device to connect with, then you don’t need to scan for the device (with or without filter) and connect it.
- StartDiscovery + Pair + Connect => ConnectDevice
How you will have MAC address before scanning?
- When you have other communication (wired or wireless) medium to exchange the MAC address
- For example, NFC OOB can be used to exchange the MAC address
- Testing Bluetooth with same device (MAC address known)
In such cases ConnectDevice can be directly called with “MAC address” of the bluetooth device to connect with as argument (as string, not as object path). In addition to the MAC address, Address Type (optional argument) can also be specified as argument to this method. For simplicity and better understanding we are going stick to only MAC address.
Before using the ConnectDevice method, we need to register our own agent which needs to be called for pairing process. Again for simplicity and for better understanding we are registering “NoInputOutput” without any method callbacks. This means, our bluetooth adapters Agen capability is similar to the one in Bluetooth headset, where user doesn’t need to care about pairing authentication. We will explore in detail about Agen API and all the methods in next blog before getting into device-api.
This example program takes the MAC address (XX:YY:ZZ:AA:BB:CC format) as argument which is directly fed into ConnectDevice method. Also note that this example uses Linux signal handler for SIGINT (Control + c from console) to gracefully handle the program exit.
21 Comments
hi there your guys BLOG example about BLE base on GIO and Glib are amazing!!!
Please keep going.
Question:how can we get the Node Information and Methods ?not only the properties.
like commod line: $ gdbus introspect –system –dest org.bluez -o /org/bluez/hci0/
interface org.bluez.Media1 {
methods:
RegisterEndpoint(in o endpoint,
in a{sv} properties);
UnregisterEndpoint(in o endpoint);
RegisterPlayer(in o player,
in a{sv} properties);
UnregisterPlayer(in o player);
signals:
properties:
};
interface org.bluez.NetworkServer1 {
methods:
Register(in s uuid,
in s bridge);
Unregister(in s uuid);
signals:
properties:
};
node dev_A4_17_31_4D_C6_7C {
};
node dev_C0_E6_30_BD_63_C1 {
};
dbus introspection is to find the list of available methods with its arguments (using “org.freedesktop.DBus.Introspectable.Introspect“). To find the real value of the property, you need to use “org.freedesktop.DBus.Properties.GetAll“. So both are completely different methods. So you need to use them accordingly.
Comments in Linumiz are controlled by admins to avoid spams. So your comments with answers will appear with some delay.
Hi!
Your posts regarding how to use DBUS for BlueZ are amazing!
I need now to be able to retrieve the list of services and characteristics of the device I just connected to? Then I will need to write some characteristic..
For example, using bluetoothctl, I am able to connect to a device . When it is connected, it displays all the services and characteristics of the peer like:
[NEW] Primary Service
/org/bluez/hci0/dev_98_7B_F3_65_83_32/service0019
0000180a-0000-1000-8000-00805f9b34fb
Device Information
How can I get those information directly from my application? Then how to read/write a characteristic?
Thank you very much!!
You should be able to read the value using DBUS method calls in here : https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/gatt-api.txt#n62 or you can directly read the property using the similar example here: https://www.linumiz.com/bluetooth-get-adapter-controller-properties-using-gdbus/.
The example above was used to read the property of the adapter, but the same example can be adapted to read the device property or gatt details.
Hi, i would like to pair a device which i know the adress, I can’t manage to use this code.
Thank you.
You don’t need
ConnectDevice
API for pairing the device. The sequence is,Scan for the device using StartDiscovery
Once the device is appeared, trust the device
Call pair API in the device
Unfortunately the blogs cover only adapter API so far and the device API’s are in progress.
Hi again, thank you for your quick answer ! I’m sorry I wasn’t precise enough in my question. I am trying to pair with a SensorTag from TI (http://www.ti.com/ww/en/wireless_connectivity/sensortag/), working in BLE, in order to get its informations from a PC running on Ubuntu 14.04 LTS. Your bluez_adapter_scan() function works well and actually print the SensorTag info on the terminal, with its MAC adress. We are now trying to pair with the device, and initially used your bluez_adapter_connect() function in order to do that. Now thanks to your answer we understand that we shouldn’t use the ConnectDevice API used in this program, but we are still wondering how to trust and pair with it as you said after it appears with StartDiscovery, as Trusted is only a device’s property ?
Thank you !
When a new device is appeared, you will get it’s object path. Now you need to use the device interface and object path to communicate with the device itself.
Assuming you device mac is XX:YY:ZZ:AA:BB:ZZ and your adapter recognized as hci0, then /org/bluez/hci0/dev_xx_yy_zz_aa_bb_cc is your device path. With this,
you should use,
Service: org.bluez
Interface: org.bluez.Device1
Object Path: /org/bluez/hci0/dev_xx_yy_zz_aa_bb_cc
these details to access all the methods and properties in device api.
You may also need to implement bluez pairing agent if you are using PIN (either fixed or dynamic) for the pairing process using “Pair” API.
If you have more query and request, please feel free contact us me parthiban@linumiz.com
Hello, your post very helped for me
Can you tell me please, when device api’s will be ready?
Thank you!
I have completed a simple agent a while back and but not yet blogged it. Device api is still in progress.
For agent related, please see
https://stackoverflow.com/a/52202563/2689839
https://stackoverflow.com/a/52128757/2689839
https://stackoverflow.com/a/51535830/2689839
Please contact me at parthiban@linumiz.com for device API related examples and on-going work.
Hi,
I have tested your code to connect with the mac id which I have passed to connect and able to do connection establishment.But Can you help me how to send data and receive data using Bluez.
Regards
srikanth.
Hi Srikanth,
If you are using LE, use GATT profile and read the services and characteristics. In classic case, you need to know which profile you are using. For example, profiles like A2DP you need to read and write data using file descriptor shared by the NewConnection API from DBUS.
You can refer some examples in Bluez-ALSA project for classic audio profiles. Regarding LE profiles, I don’t have examples ready now. Feel free to contact us for more support.
Thanks,
Parthiban N
Hi Parthiban,
I have paired the device by using pair command on bluetoothctl and trying to connect the device by using the api which you have mentioned above but facing the below error.
Could you please advice.
natraj@natraj-VirtualBox:~/new$ ./build/xbbld D8:63:75:F7:80:91
Unable to get result: GDBus.Error:org.freedesktop.DBus.Error.UnknownMethod: Method “ConnectDevice” with signature “a{sv}” on interface “org.bluez.Adapter1” doesn’t exist
Thanks,
Natraj M
Natraj, You need to run bluetoothd in experimental mode as this feature is still marked as experimental i.e “bluetoothd -E”
Dear sir,
I am trying to automatically connect from Raspberry to my Zephyr bluetooth dongle providing custom services: pressing a button and switchning a LED diode (NORDIC LBS (LED BUTTON SERVICE)).
I am able to control both characteristic via Nordic Android APP BLinky, but I want to achieve the same functionality utilizing Linux BlueZ stack. I found another project where I can catch button events via bluetooth, but the code it automatically connecting to a device with certain UUID therefore having multiple dongles with muliple buttons and LEDs serving the same service with the same UUID will probably lead to malfunction, therefore I want to connect to each dongle via MAC address.
Bluetoothctl can connect to my dongle just via commands:
power on; scan on; connect MAC_ADDRESS;info
And the bluetoothctl C code is using some “Connect” proxy call (not the “ConnectDevice” call) to connect using the MAC address, but I want to use you ConnectDevice command to dbus.
But when your compiled example in such a way:
./bluetoothconnect E4:A8:10:11:BF:D0
yields corresponding response:
Unable to get result: GDBus.Error:org.bluez.Failed:
Do you have any ideas what might be wrong?
I enabled experimental bluez, but on Raspberry bluetoothd service needed certain modification in order to start the service without any errors. Such an error was discussed multiple times on RPi forums.
Thank you
Maybe I have to replace ConnectDevice call with code snippet I see in bluetoothctl source code enclosed below, but is it really necessary? Probably I am doing something wrong as I am complete newbie in bluetooth, but with bluetoothctl I can connect to my dongle with command: connect, then what is wrong? I used the same example code, just the MAC address is different. Is it something wrong with Raspberry bluetooth?
GDBusProxy *proxy;
if (check_default_ctrl() == FALSE)
return bt_shell_noninteractive_quit(EXIT_FAILURE);
proxy = find_proxy_by_address(default_ctrl->devices, argv[1]);
if (!proxy) {
bt_shell_printf(“Device %s not available\n”, argv[1]);
return bt_shell_noninteractive_quit(EXIT_FAILURE);
}
if (g_dbus_proxy_method_call(proxy, “Connect”, NULL, connect_reply,
proxy, NULL) == FALSE) {
bt_shell_printf(“Failed to connect\n”);
return bt_shell_noninteractive_quit(EXIT_FAILURE);
}
Hi Ivo,
Bluetoothctl got it’s own implementation of gdbus based on DBus RAW API’s. So referring that code may not be ideal for the application implementation.
Not sure if you are still stuck with the issue and need help. If so, write me to parthiban@linumiz.com
Hi Parthiban,
Instead of “ConnectDevice” method , i am using “Connect” method in org.bluez.Device1 interface . But i could not connect once after bluetoothd starts.
In this case adapter has powered on, discoverable on and pairable on . If i connect and disconnect from the remote device , then i could connect the remote device using “Connect” method.
Thanks,
Asik
Hi Adbul Asik,
What’s the error you are getting in “Connect” call?
Hi there! Do you use Twitter? I’d like to follow you
if that would be ok. I’m definitely enjoying your blog and look
forward to new posts.
my web page … 먹튀검증
We are in the middle of page migration. The team is handling the update. You can follow me in LinkedIn https://www.linkedin.com/in/parthitce/ and not much active in Twitter but x.com/parthitce or x.com/linumiz should work IMO