Hinweis: Diesen Blog schreibe ich ausnahmsweise auf Englisch, weil das Thema für viele Rasperry-Pi-Bastler interessant sein könnte.
Some days ago I started a project where I assembled a Bluetooth low energy (BLE) device that sends out some sensor data. In addition to reading these data with a smartphone I also want to receive and process them with a Raspberry Pi. However, it turned out that working with BLE on the Raspberry Pi is not as easy as I thought, especially if you want to write applications in Java or C/C++.
Finally I found a way to do it, and I would like to share it here for people who are looking for an easy entry into the world of BLE on the Raspberry Pi.
As prerequisites you need nothing more than a current Raspbian Jessie installation and a Bluetooth LE capable USB stick. The latter might not be necessary for a Raspberry Pi 3 since it should have Bluetooth already on board. And of course, a BLE device to test your setup is also quite helpful.
The setup procedure for the stuff you need to develop BLE applications consists of three steps:
- Install and test the bluez software stack
- Install cmake
- Install and test the tinyb library from the Intel® IoT Developer Kit.
If you want to work with Python you can stop already after the first step and try for instance the library from Adafruit (https://github.com/adafruit/Adafruit_Python_BluefruitLE) or the one from Ian Harvey (https://github.com/IanHarvey/bluepy).
1. Install and test bluez
If you look at the bluez web page (www.bluez.org) you will find that it is the “official Linux Bluetooth stack”. But what does that mean?
After installing bluez you can communicate with Bluetooth devices by using the D-Bus message bus system. A good introduction to that topic can be found in the paper “Playing BlueZ on the D-Bus”.
You might notice that the Raspbian Jessie installation already comes with bluez installed. However, it is an old version and BLE support is still patchy. So it’s best to remove it and install the latest version, which was 5.43 at the time of writing. The following command does the job:
> sudo apt-get --purge remove bluez
After you removed the old bluez installation you can do the following:
> sudo apt-get update > sudo apt-get install -y libusb-dev libdbus-1-dev libglib2.0-dev libudev-dev libical-dev libreadline-dev > cd ~ > wget https://www.kernel.org/pub/linux/bluetooth/bluez-5.43.tar.gz > tar xvf bluez-5.43.tar.gz > cd bluez-5.43 > export LDFLAGS=-lrt > ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --enable-library -disable-systemd > make > sudo make install > sudo cp attrib/gatttool /usr/bin/ > sudo cp ./src/bluetoothd /usr/local/bin/ > hash -r > sudo nano /etc/rc.local
Scroll to the end of file and just before the ‚exit 0‘ line add the following line
/usr/local/bin/bluetoothd --experimental &
Press Ctrl-O and enter to save the file, then Ctrl-X to exit the editor. The experimental parameter is important since without it some needed plugins will not be loaded.
After you have done all that you should be able to communicate with your BLE device. But first you might have to switch on the BLE stick on the Raspberry.
Check if the Bluetooth hardware is switched on by entering
> hciconfig
If it is down just enter
> sudo hciconfig hci0 up
After that try the following
> sudo hcitool lescan
If you see your BLE devices listed you are nearly done. You should now test if you can connect to a device in the list. But take care: It is important to choose the correct address type (random or public). My device had “random” device address which means that the module uses a 48-bit address that was randomly generated during the manufacturing process.
To test the connection to a BLE device that was discovered by the scan you can enter:
> sudo hcitool lecc --random <address>
where you replace <address> with the BLE device address (MAC address format XX:XX:XX:XX:XX:XX). Alternatively, for an interactive session you can use:
> sudo gatttool -t random -b <address> -I
In both commands you should omit the “random” parameters if your device has a public address.
2. Install cmake
Although cmake can be installed by using the package manager (apt-get) you will only get an old version. To install the tinyb library later we need a newer version that can be installed by the following commands.
If you already installed the version from the repository remove it with
> sudo apt-get --purge autoremove cmake
Afterwards just execute the following lines (assuming 3.6.2 is the current stable release):
> sudo apt-get install build-essential > cd ~ > wget http://www.cmake.org/files/v3.6/cmake-3.6.2.tar.gz > tar xvf cmake-3.6.2.tar.gz > cd cmake-3.6.2 > ./configure > make > sudo make install > hash -r
Consider having some coffee during installation since it really takes time to configure the Makefile and build cmake.
Since cmake does not configure the currently installed JDK you can either manually correct the following file
/usr/local/share/cmake-3.6/Modules/FindJNI.cmake
or (as I did) just export the following variables (replace the path with your JDK installation directory; I used Java 8 JDK from Oracle):
export JAVA_HOME=/usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt export JAVA_AWT_LIBRARY=/usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt/jre/lib/arm/libawt.so export JAVA_JVM_LIBRARY=/usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt/jre/lib/arm/server/libjvm.so export JAVA_INCLUDE_PATH=/usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt/include export JAVA_INCLUDE_PATH2=/usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt/include/linux export JAVA_AWT_INCLUDE_PATH=/usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt/include
These export statements are important to correctly build the tinyb library for Java.
3. Install tinyb
tinyb (https://github.com/intel-iot-devkit/tinyb/) is a BLE library from the Intel® IoT Developer Kit. If you want to develop applications in Java or C/C++ and do not want play with D-Bus yourself it is extremely helpful. With bluez and cmake set up as described before it should be a piece of cake.
Just do the following:
> cd ~ > git clone https://github.com/intel-iot-devkit/tinyb > cd tinyb > mkdir build > cd build > cmake -DBUILDJAVA=ON .. > make > sudo make install
That should have been everything. To test if tinyb is working you can execute the following commands:
> cd ~/tinyb/build > sudo ./examples/hellotinyb <address>
Or for Java:
> cd ~/tinyb/build > sudo su > export LD_LIBRARY_PATH=/usr/local/lib > java -cp examples/java/HelloTinyB.jar:/usr/local/lib/java/tinyb.jar HelloTinyB <address> > exit
Although the HelloTinyB programs were designed to work with the TI sensor tag they should be able to discover the BLE device and list its services.
The Java and C++ examples coming with the tinyb library should be sufficient to start building your own applications. In addition the Intel web page https://software.intel.com/en-us/java-for-bluetooth-le-apps contains an introduction for how to write a BLE Java application.
Final Remarks
I hope this little blog can help you to start writing BLE applications quickly without spending too much time to setup the BLE basic stack on the Raspberry Pi. If you find it helpful please leave me a comment.
And finally, for a general introduction to BLE I can highly recommend this guide from Adafruit: https://learn.adafruit.com/introduction-to-bluetooth-low-energy/introduction.
PS: Stay tuned for the blog about setting up my BLE sensor project.
Hi MichaelHaugk,
I follow your guide for my raspberry pi 3, but after install bluez 5.43, I had checked by cmd: systemctl status bletooth
● bletooth.service
Loaded: not-found (Reason: No such file or directory)
Active: inactive (dead)
So, could you help active bluetooth device on Raspberry pi 3?
Hi thanhlu,
It’s perfectly fine that you don’t see bluetooth running as a service since the „disable-systemd“ switch was used in the configure-command for bluez. If you followed my instructions above you should see the bluetooth daemon running if you enter (it was started using „rc.local“): ps -eF | grep bluetoothd
All the other commands should work as well (e.g. sudo hcitool lescan). This means bluetooth le is working well.
If you would like to install the daemon as a service, I can recommend this page from Adafruit since some more steps are involved: https://learn.adafruit.com/install-bluez-on-the-raspberry-pi/installation
Please let me know, if you still experience problems with bluetooth.
Best regards,
Michael
Hi Michael,
Thank you for your guidance. I follow https://learn.adafruit.com/install-bluez-on-the-raspberry-pi/installation and I have installed Bluez successfully.
Best regards,
Thanhlu
Thanks for the helpful blog. I have a problem setting parameter JDK Oracle:
export JAVA_HOME=/usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt
export JAVA_AWT_LIBRARY=/usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt/jre/lib/arm/libawt.so
export JAVA_JVM_LIBRARY=/usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt/jre/lib/arm/server/libjvm.so
export JAVA_INCLUDE_PATH=/usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt/include
export JAVA_INCLUDE_PATH2=/usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt/include/linux
export JAVA_AWT_INCLUDE_PATH=/usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt/include
In my case JDK is located in /usr/local/java/jdk1.7.0_79….but i cannot find inside jre/lib any arm folder….infact when i launch cmake i got errors.
Can you help me please?
Hi Alex,
As long as the libraries are present in your jdk installation there shouldn’t be any general problem. Just try to find the path where the libraries are located in your local java installation, e.g. by
cd /usr/local/java/
.find . -name "libawt.so" -print
Then you just can set the paths correctly (see e.g. https://cmake.org/cmake/help/v3.0/module/FindJNI.html ).
Once you know where the libraries are you can alternatively modify FindJNI.cmake, see for example: http://stackoverflow.com/questions/17636166/cmake-find-packagejni-not-work-in-ubuntu-12-04-amd64 ).
Hope that this helps. Please let me know.
Best regards,
Michael
Hi Micheal, thanks for your help. Really appreciate. I removed the build folder inside tinyb with older JVM include and now I can create the tinyb.jar needed for my BLE project.
Now I have to communicate from my desktop PC to a Bluetooth LE 4.0., I included tinyb.jar in classpath and try the Intel example „HelloTinyb.class“. When I try to launch it, i have this exception:
Native code library failed to load.
java.lang.UnsatisfiedLinkError: no javatinyb in java.library.path
Can you please help me? Thanks in advance
Hi Alex,
you need to tell Java where the native library „libjavatinyb.so“ is located. In my case it is installed in „/usr/local/lib“.
Therefore, I used „export LD_LIBRARY_PATH=/usr/local/lib“ before executing Java. If you followed my instructions above, the library is probably installed in the same directory and the command to set the environment variable should work for you as well.
Best regards,
Michael
Hi again Micheal, resolved starting Eclipse in a bash with: export LD_LIBRARY_PATH=/usr/local/lib
Not working using Run Configurations VM arguments.
Resolved one problem, here now with a new one:
When i try to connect (in my case):
BluetoothDevice sensor = getDevice(„D0:4E:4A:11:CB:C7“);
boolean connect = sensor.connect();
I got an exception:
Exception in thread „main“ tinyb.BluetoothException: GDBus.Error:org.bluez.Error.Failed: Software caused connection abort
Thanks in advance for any reply.
Bye
Hi Alex,
I’m afraid that I cannot help you here without further analysis or debugging. And the GDBus interface has some flaws you might need to work around.
My best advice would be: Before you start to work with tinyb make sure everything else (i.e. your bluetooth setup) works correctly. Use the gatttool in interactive mode (see above) and if the session is started enter „connect“. If this works and you can read and/or write to the services of your device using the gatttool it should work with tinyb as well. With that you also make sure that your devices advertises everything correctly and the services are working as expected (if you built and programmed your own BLE device).
In a second step you need to make sure that you really get a valid device back from your method call above.
Once that also works your program will probably run without exceptions.
Best regards,
Michael
sudo hciconfig hci0 up and try angian
It seems that with bluez 5.44 the hcitool has been declared deprecated. In order to still use it you have to build it with –enable-deprecated (see https://bugs.archlinux.org/task/53110).
If I have time I will update this guide to reflect the changes.
Is it possible to use these steps to build Bluez 5.44 without –enable-deprecated? The steps aren’t working for me for this latest Bluez version.
I still didn’t find the time to update this guide to reflect the changes in 5.44. I guess as long as you rely on the D-Bus interface it should work fine. However, I need to check.
Hi Michael. Thanks so much for writing this up. My problem is that after following step 1 my raspberry pi 3 bluetooth adapter stops working. It says no adapter found. I tried with external dongle as well but can’t seem to find any adapter. Basically after executing „sudo apt-get –purge remove bluez“ it removes not only bluez but also firmware for bluetooth and even after installing bluez-5.43 it never comes up.
>bluetoothd -v
5.43
>sudo systemctl status bluetooth● bluetooth.service
Loaded: not-found (Reason: No such file or directory)
Active: inactive (dead)
>sudo hciconfig hci0 up
Can’t get device info: No such device
>sudo bluetoothctl
[bluetooth]# show
No default controller available
>sudo hcitool lescan
Could not open device: No such device
Hi Amit,
Thank you very much for your feedback.
Removing bluez should usually not remove any drivers. However, since I didn’t check the latest Debian/Raspbian versions I don’t know if it is still necessary to remove bluez or if a version is included that is supported by tinyb.
But just to check: You see the bluetooth devices on a freshly installed OS?
Best regards,
Michael
What can I say ? THANK YOU
I’ve been struggling with BLE for 5 days now, and I finally made it, thanks to you !
I just had to install cmake with apt-get install, cause when I was doing it manually, ‚./configure‘ was making an error (file not found)
But I finally suceeded, connected my BLE Arduino Feather 32u4 with ‚bluetoothctl‘ (and not hcitool !) and then I ran the example, and IT WORKED !
Thanks a lot, you just saved my school project !
You are welcome. I’m very happy that I could help you.
Best regards,
Michael
Hello. I’m trying to setup a connection between Adafruit Feather 32u4 and my laptop. Can you please let me know how did you do it using „bluetoothctl“ and were you running an example script on the feather board?
Hi Michael,
congratulations — this is a very good article, and at last I’ve managed to get a working Bluetooth system on my Pi. At least as far as the examples go. But I need a bit of help: I’m a bit new to Linux and raw GCC (G++), having done all my previous development on IDE’s which offer a front end (eg Xcode on Mac OS).
As in your tutorial, everything worked great, including using the built version of hellotinyb
As a first step to writing my own software, I’ve simply tried compiling the vanilla hellotinyb.cpp example, having first copied it to a new directory (as my own code will be in such a new directory).
If I try a simple g++ hellotinyb.cpp -o hello, I get an error becasue tinyb.hpp isn’t found. If I add -I ~/tinyb/api (which is where it is), G++ generates pages of errors, including from the standard libraries. Something is wrong.
Can you offer any suggestions?
thanks,
Richard
Solved, after a night’s sleep!
We had many power cuts on the day I was building the package and eventually I didn’t run the make install command!
Then after extending the scrollback (a lot!) I could find the initial errors saying that I need to include the option -std+gnu++11.
After specifically including the library (-ltinyb) everything seems good.
cheers,
Richard
Hi Richard,
I’m glad to hear that it worked out for you!
Cheers,
Michael
Thx very much for this guide, it helped me get my first BLE project running on the RPI. Very much appreciated!
Furtunately: in the September release of Raspbian, the versions of bluez and cmake are now up to date, and can be apt-getted, so steps 1 and 2 are now out-of-date.
Inspired by your guide, I wrote a small post on the new situation: https://nisone.wordpress.com/2017/09/30/java-bluetooth-low-energy-on-the-raspberry-pi-3-september-2017-update/
Thank you very much for your feedback! It is very much appreciated and it keeps me motivated to continue writing blogs.
I faced below DBUS related issue. Installed on my Ubuntu PC.
Issue logs:
Exception in thread „main“ java.lang.RuntimeException: Error getting object manager client: Error calling StartServiceByName for org.bluez: GDBus.Error:org.freedesktop.DBus.Error.Spawn.ChildExited: Launch helper exited with unknown return code 1
at tinyb.BluetoothManager.getNativeAPIVersion(Native Method)
at tinyb.BluetoothManager.getBluetoothManager(BluetoothManager.java:304)
at HelloTinyB.main(HelloTinyB.java:109)
Please help
Hallo,
danke für dein Tutorial, das hat mir schon sehr viel geholfen.
Ich würde gerne das Java example abändern auf meine Bedürfnisse und würde gerne wissen wie ich denn dann daraus die .jar File compelieren kann?
Ich sehe den Wald vor lauter Bäume nicht mehr 🙂
Danke schon mal
Gruß Pano
Hallo Pano,
Vielen Dank für die positive Rückmeldung!
Zum Java-Paket erstellen:
Nach dem Compilieren kann man das JAR-File manuell erstellen, wenn man möchte: https://docs.oracle.com/javase/tutorial/deployment/jar/build.html
Auf der anderen Seite verwende ich selbst eine IDE (Eclipse), bei der man fertige (compilierte) Java-Projekte einfach per Maus-Click als JAR-File exportieren kann. Ich denke, das ist die einfachste Möglichkeit.
Hi Everyone
Has anyone used tinyb to send data? Is there a way, or potentially a supplementary libary?
Tx
Mike