BLE Examples
Bluetooth Low Energy Examples
Many Technologic Systems' products offer on-board support of Wi-Fi and Bluetooth via a soldered down module. In applications without on-board support, Bluetooth connectivity can still be achieved with a USB dongle.
This document will focus only on products that use the on-board modules. While these examples should work just the same, external USB modules may require additional configuration and support that is not covered here. Additionally, these examples will only cover Bluetooth Low Energy and not Bluetooth Classic modes.
The primary provider of Bluetooth support in Linux is the BlueZ project. Many distributions provide their own release of BlueZ packages. However, with how quickly BLE and Linux evolve, this may not be the best route for up-to-date support unfortunately.
Below, we have a set of instructions for both installing and using BlueZ with some of our products. Additionally, BlueZ provides a set of example scripts for testing functionality and for use as a starting point for development. The instructions below provide setup and use cases for these scripts in order to give known working examples. Additionally, we've done testing with external APIs and have provided examples that we have found working with this as well.
This is not intended to be a development guide, it is simply an introduction with known working and testing examples in order to get BLE up and running with Technologic Systems' products.
For those unfamiliar with the differences between Bluetooth Classic and BLE modes, we strongly suggest doing some background research. The main difference of note is that Classic Bluetooth offered many different profiles targeted at a wide range of concepts from notification to data transport. BLE on the other hand was designed with notification and signaling in mind. BLE has a focus on low power, low communication latency, and long battery lifetimes. More importantly, it removes restrictions in data formats by using the single Generic Attribute Profile (GATT) for all communication with some established data standards on top of this. This adds immensely to the flexibility of Bluetooth LE, but moves the complexity of communication to the application layer.
Note that all of the examples assume the unit is running at least Debian Stretch with at least a 4.9 kernel. Using older distributions or kernels may result in compatibility or functionality issues.
BlueZ
Installing BlueZ From Source
At the time of writing this, version 5.61 is the latest BlueZ release. The following examples will download, build, and install BlueZ directly on the target device. Compilation directly on the device will be far slower but does not have the prerequisite of a properly set up cross build system. Cross compilation of BlueZ is possible, but is beyond the scope of this document.
First, since most of our products ship with BlueZ pre-installed from the distribution package manager, this will need to be removed:
apt-get purge "bluez*"
Ensure all build requirements are met (note that some examples use Python 2 while others use Python 3):
apt-get update && apt-get install -y git libglib2.0-dev libglib2.0-0 libdbus-1-dev libdbus-1-3 libudev-dev libudev1 libical-dev libreadline-dev python3-dbus python3-pip python-dbus docutils-common
Next, download the sources for BlueZ 5.61:
wget https://www.kernel.org/pub/linux/bluetooth/bluez-5.61.tar.xz
tar xvf bluez-5.61.tar.xz
Configure, build, and install BlueZ:
cd bluez-5.61
./configure --enable-library --enable-test --enable-deprecated && make install
systemctl enable bluetooth
systemctl start bluetooth
Note: | If using a distribution older than Debian Stretch, it may be necessary to add --disable-manpages to the configure options.
|
From here, the example tools will be installed to /usr/local/lib/bluez/test/
. We will be using this later.
Running the Examples
With BlueZ and its examples built and installed, it's now possible to start running some of the examples and using them for further development. Below, we highlight a few different examples.
Before running any of the examples, the Bluetooth device must be up and enabled. See the specific device's manual's Bluetooth section for information and steps on how to bring up and enable the on-board Bluetooth device.
However! If the manual's instructions use the hciconfig
command, do not run this command! The reason is that recent versions of BlueZ have moved to a more centralized control scheme using bluetoothd
. Running the hciconfig
command in any way can cause the Bluetooth service to enter an invalid state. If needed, the use of hciattach
is safe for attaching the device to the kernel, but btattach
is preferred where applicable.
Additionally, most of the examples will require a compatible external device, e.g. a smartphone or other peripheral that is able to connect to other BLE nodes.
Discover Devices
This simple script will scan for and print any nearby BLE devices that are detected by the BLE module on the unit.
Prerequisites
- The Bluetooth device must already be set up via the device's manual's instructions (without the use of the
hciconfig
command!) andbluetoothd
started via system as noted above. - Be running as
root
user or a user with proper permissions.
Running
The example can be started with:
root@tsimx28:~# bluetoothctl power on Changing power on succeeded root@tsimx28:~# /usr/local/lib/bluez/test/test-discovery [ XX:XX:XX:XX:XX:XX ] AddressType = public Name = ABC123 Paired = 0 ServicesResolved = 0 Adapter = /org/bluez/hci0 LegacyPairing = 0 TxPower = 6 Alias = ABC123 Connected = 0 UUIDs = ... RSSI = -48 Trusted = 0 Blocked = 0 ...
The example will continue to run and print newly discovered devices until Ctrl+c
is pressed on the terminal.
Example Advertisement
In order for a BLE device to be found via a search, it needs to be set up to advertise. This example will create an advertisement with a customized name.
Prerequisites
- The example was tested against a smartphone with BLE capabilities, using a simple BLE monitor tool.
- The Bluetooth device must already be set up via the device's manual's instructions (without the use of the
hciconfig
command!) andbluetoothd
started via system as noted above. - Be running as
root
user or a user with proper permissions.
Running
Before this is run, we're going to set a custom advertising name to make it more identifiable.
sed -i -e "s/'TestAdvertisement'/'TS_BLE_Demo'/" /usr/local/lib/bluez/test/example-advertisement
Additionally, some embedded modules are not able to handle longer advertisement lengths, we're going to comment out an example nonstandard advertisement type in order to support all platforms.
sed -i -e "s/self.add_data/#self.add_data/" /usr/local/lib/bluez/test/example-advertisement
Run the example with:
root@tsimx28:~# /usr/local/lib/bluez/test/example-advertisement & Advertising forever... GetAll returning props Advertisement registered root@tsimx28:~#
If there are any errors, check that all of the prerequisites have been satisfied.
On another BLE compatible device, running a scan will return our device named "TS_BLE_Demo." This device can be connected to, the example will start up a number of simple services. For example, the device name can be read. The following screenshot from a smartphone reads the "Device Name" value.
Example GATT Server
The BlueZ example GATT server emulates a dummy device with a dummy battery. It demonstrates being able to do active reads of a BLE device as well as subscribing to push notifications from a device.
Prerequisites
- The example was tested against a smartphone with BLE capabilities, using a simple BLE monitor tool.
- The Bluetooth device must already be set up via the device's manual's instructions (without the use of the
hciconfig
command!) andbluetoothd
started via system as noted above. - Be running as
root
user or a user with proper permissions. - Set up and run the Example Advertisement example. This is needed so that the BLE device can be advertised and discovered.
Note: | Due to caching on some devices, it may be necessary to completely exit any BLE applications/tools, and potentially even power-cycling the BLE device itself on any devices connecting to the example GATT server below. This has been observed to be necessary on at least one specific smartphone that was used to connect to the unit's on-board BLE module running these examples. |
Running
Run the example with:
root@tsimx28:~# /usr/local/lib/bluez/test/example-gatt-server Registering GATT application... GetManagedObjects GATT application registered root # The following lines will not be printed until the device connects and does a read of the "Battery Level" service Battery Level read: 100 Battery Level read: 100 Battery Level drained: 98 Battery Level drained: 96 Battery Level drained: 94 ... root # The following lines will not be printed until the device connects and subscribes to the "Heart Rate Measurement" service Update HR Measurement Simulation Updating value: [dbus.Byte(14), dbus.Byte(93), dbus.Byte(0), dbus.Byte(0)] Updating value: [dbus.Byte(6), dbus.Byte(127)] Updating value: [dbus.Byte(6), dbus.Byte(108)] Updating value: [dbus.Byte(6), dbus.Byte(128)] ... root # The following lines will not be printed until the device connects and interacts with the "characteristic for testing" services TestCharacteristic Write: dbus.Array([dbus.Byte(192), dbus.Byte(255), dbus.Byte(238)], signature=dbus.Signature('y')) TestSecureCharacteristic Write: dbus.Array([dbus.Byte(222), dbus.Byte(250), dbus.Byte(206)], signature=dbus.Signature('y')) TestCharacteristic Read: dbus.Array([dbus.Byte(192), dbus.Byte(255), dbus.Byte(238)], signature=dbus.Signature('y')) TestSecureCharacteristic Read: dbus.Array([dbus.Byte(222), dbus.Byte(250), dbus.Byte(206)], signature=dbus.Signature('y')) ...
With the connecting device, it is possible to read from or subscribe to the Battery Level
service. The running example will print "Battery Level read: ..." each time the battery is manually read. When subscribed to, the connecting device will receive periodic updates of the battery level. When an update goes out, the running example will print "Battery Level drained: ..." with the value also being sent to any subscribed devices. The following screenshot is an example of what a connected device would see.
With the connecting device, it is possible to subscribe to the Heart Rate Measurement
service. The running example will print simulation values to the terminal once every second, with the same values being sent to any subscribed devices. The following screenshot is an example of what a connected device would see.
With the connecting device, it is possible to write and read multiple of the characteristic for testing
services. Anything that is written to these services can be read back independently. In the example output above, the hex value 0xC0FFEE was written and read back from the first service, while 0xDEFACE was written and read back from the third service.
When done, press Ctrl+c
to end the example and return to the command line, leaving the advertising example running in the background still.
Example BLE Library python-bluezero
In order to continue with our examples, python-bluezero will be used. The python-bluezero project aims to provide a BlueZ API with zero boilerplate code that would normally be required. This API provides a number of very simple examples for testing and forward development of BLE applications. The API is fairly well documented and makes BLE application development in Python quite simple.
Note that Technologic Systems has no affiliation with this project. We simply have found that it served the purpose of providing real examples with a quick development thanks to its abstraction. At the time of writing this article, python-bluezero has had recent development and shows no signs of stalling. There are many different APIs for communicating with BlueZ and DBus; we are not able to recommend a particular API over any others.
Installing python-bluezero
The following commands can be used to clone the project and install it. Be sure to have first installed BlueZ from source before installing and running the examples:
pip3 install evdev aioblescan
git clone https://github.com/ukBaz/python-bluezero
cd python-bluezero
git checkout f9179dc057d1428fd2d95eab82db4172c18d5e0b
python3 setup.py install
cp examples/ukBaz.bluezero.conf /etc/dbus-1/system.d/ #This is needed to register python-bluezero as a DBus peripheral application. The provided file is purely an example and may need modifications for specific situations.
Note: | The commit of python-bluezero that is checked out is fairly old at this point, however, newer releases have a dependency of Python 3.6 which is not available on our platforms running Debian Stretch or older. If using newer distribution, it is advised to use latest release. |
Eddystone-URL Beacon
Eddystone is an open beacon format developed by Google and designed with transparency and robustness in mind. The Eddystone format can provide several different kinds of payloads including unique ID, URL broadcasting, and even a time-varying beacon that can be resolved to a stable identifier.
Prerequisites
- The example was tested against a smartphone with BLE capabilities, using a simple BLE beacon scanning tool.
- The Bluetooth device must already be set up via the device's manual's instructions (without the use of the
hciconfig
command!) andbluetoothd
started via system as noted above. - The python-bluezero project installed as outlined above.
- Be running as
root
user or a user with proper permissions.
Note: | Due to caching on some devices, it may be necessary to completely exit any BLE applications/tools, and potentially even power-cycling the BLE device itself on any devices connecting to the example GATT server below. This has been observed to be necessary on at least one specific smartphone that was used to connect to the unit's on-board BLE module running these examples. |
Running
The example can be run with:
root@tsimx28:~/python-bluezero# python3 examples/eddystone-url-beacon.py Advertisement registered
The beacon can be observed on a device running a scanner such as the tool below:
Eddystone Beacon Scanner
This example will constantly poll for and print out Eddystone format beacons. This tool will readily print URL and UID beacons, but does not appear to correctly handle EIM or TLM beacons at this time. This may change in the future.
Note: | There is a bug present in the Python binary distributed with Debian Stretch that prevents this example from working correctly. It is advised to either move to Debian Buster (or newer) or move to Buildroot. In both of these, Python sockets with respect to BLE are correctly implemented allowing aioblescan to work correctly. Please contact us with any questions regarding these issues. |
Prerequisites
- The example was tested against a smartphone with BLE capabilities, using a simple BLE beacon emulation tool.
- The Bluetooth device must already be set up via the device's manual's instructions (without the use of the
hciconfig
command!) andbluetoothd
started via system as noted above. - The python-bluezero project installed as outlined above.
- Be running as
root
user or a user with proper permissions.
Running
The example can be run with:
root@tsimx28:~/python-bluezero# python3 examples/eddystone-scanner.py ... New Eddystone data: url = https://www.embeddedTS.com/ mac address = XX:XX:XX:XX:XX:XX tx_power = -69 rssi = -78 ... New Eddystone data: name space = 0xC7ACE534120F67D5345A rssi = -72 mac address = XX:XX:XX:XX:XX:XX tx_power = -65 instance = 0x42
Using aioblescan for Eddystone TLM Beacons
The latest version of the Python library aioblescan
correctly supports and prints Eddystone TLM beacons. Using the beacon emulator above, or a hardware beacon such at the ON Semi RSL10-COIN-GEVB demo board, TLM packets can be received and decoded:
root@tsimx28:~# python3 -m aioblescan -e Google Beacon {'tx_power': 0, 'url': 'https://www.onsemi.com/b-idk', 'mac address': '60:c0:bf:26:df:db', 'rssi': -51} ... Google Beacon {'temperature': 22.75, 'battery': 2478, 'uptime': 78100, 'pdu count': 109} Google Beacon {'tx_power': 0, 'url': 'https://www.onsemi.com/b-idk', 'mac address': '60:c0:bf:26:df:db', 'rssi': -49} ... Google Beacon {'temperature': 22.75, 'battery': 2479, 'uptime': 83000, 'pdu count': 116} Google Beacon {'tx_power': 0, 'url': 'https://www.onsemi.com/b-idk', 'mac address': '60:c0:bf:26:df:db', 'rssi': -49} ...