BLE Examples

From embeddedTS Manuals

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!) and bluetoothd 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!) and bluetoothd 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!) and bluetoothd 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!) and bluetoothd 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!) and bluetoothd 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}
...