This repo contains example projects based on pyBGAPI that implement simple Bluetooth and Bluetooth mesh applications for demonstration purposes. These examples can be used as references to implement custom Bluetooth and Bluetooth mesh applications in Python in just a few minutes without writing a single line of embedded code.
-
Install pyBGAPI.
pip install pybgapi
-
Flash the Bluetooth - NCP or Bluetooth Mesh - NCP Empty demo binary on your Wireless Development Kit using Simplicity Studio.
-
Run an arbitrary example from the repo.
python3 example/bt_empty/app.py
or
python3 example/btmesh_empty/app.py
To get started with Silicon Labs Bluetooth software, see QSG169: Bluetooth® SDK v3.x Quick Start Guide. For Bluetooth Mesh, see QSG176: Bluetooth® Mesh SDK v2.x Quick-Start Guide.
In the NCP context, the application runs on a host MCU or a PC, which is the NCP Host, while the Bluetooth stack runs on an EFR32, which is the NCP Target.
The NCP Host and Target communicate via a serial interface (UART). The communication between the NCP Host and Target is defined in the Silicon Labs proprietary protocol, BGAPI. pyBGAPI is the reference implementation of the BGAPI protocol in Python for the NCP Host.
On Linux systems, an additional CPC layer is available that provides additional security and robustness. For further details, see Co-Processor Communication.
AN1259: Using the v3.x Silicon Labs Bluetooth® Stack in Network CoProcessor Mode provides a detailed description how NCP works and how to configure it for CPC and custom hardware.
For the latest BGAPI documentation, see docs.silabs.com.
All example applications in this repo are based on the generic application classes. These classes are defined in util.py and provide all the common code that the example applications share. Therefore, the user code contains only the bare minimum without duplication. It also makes writing a custom event-driven application quite simple. The application classes have a multi-level inheritance chain, where each inheritance level adds extra features and becomes more specialized.
This class provides the skeleton for all application classes. It is responsible for connecting to an NCP Target and receiving the events in an infinite loop.
Its constructor instantiates one BGLib
object, which is accessible in its lib
attribute. This
lib
object is the interface for sending BGAPI commands to the target.
The execution of the application starts by calling the run
method. This method opens the
connection (e.g., the serial port of a WSTK board), performs a reset to get to a well-defined
state, and receives events from the NCP Target in an infinite loop. The event reception happens
in a blocking manner without timeout. It also implies that the run
method is a synchronous call,
i.e., the execution of the script will continue when the running terminates. If the running
terminates for one of the following reason, the connection will be closed and the script execution
continues:
- User interruption with the
Ctrl
+C
keys. - Programmatically calling the
stop
method. - Upon BGAPI command failure.
The execution can be started in an asynchronous mode too by calling the start
method. It starts
the run
method in its own thread and returns immediately. The main thread will terminate once all
the non-daemon threads are terminated. Please note that in this case the KeyboardInterrupt
has to
be handled in the main thread. See the Troubleshooting chapter for details.
This class extends the ConnectorApp with the following features.
Every Bluetooth SDK comes with an XAPI file that describes the actual version of the BGAPI protocol. This repo contains a copy of the XAPI file. The examples are written based on this copy. The BGAPI versions on the host and target side should be aligned. Otherwise, unexpected issues may happen. On a boot event, the version of the XAPI file and the Bluetooth stack version running on the NCP Target are compared and a warning message is printed if they do not match.
On a boot event, the Bluetooth address is read from the NCP Target and printed on the console.
The address is also cached in the address
and address_type
attributes, so it can be accessed
later without NCP communication overhead.
The BluetoothApp overrides the empty reset
method of the GenericApp that is called by the
run
method. When called, the device will restart in normal boot mode.
The BluetoothApp uses the sl_bt.xapi file by default in its constructor.
This class extends the ConnectorApp with the following features.
Every Bluetooth SDK comes with an XAPI file that describes the actual version of the BGAPI protocol. This repo contains a copy of the XAPI file. The examples are written based on this copy. The BGAPI versions on the host and target side should be aligned. Otherwise, unexpected issues may happen. On a boot event, the version of the XAPI file and the Bluetooth stack version running on the NCP Target are compared and a warning message is printed if they do not match.
Initializes the Bluetooth mesh stack in Node role. When initialization is complete, a node initialized event will be generated. This command must be issued before any other Bluetooth mesh commands. Note that you may initialize a device either in the Provisioner or the Node role, but not both.
The BtMeshApp overrides the empty reset
method of the GenericApp that is called by the
run
method. When called, the device will restart in normal boot mode without any previous node
configuration parameters. In other words, if the node was previously provisioned into a network,
it will be removed.
The BtMeshApp uses both the Bluetooth sl_bt.xapi and Bluetooth mesh sl_btmesh.xapi XAPI files by default in its constructor.
The ArgumentParser
class is derived from the standard argparse.ArgumentParser
class. This class
has default arguments optimized for the generic application classes to set up connection parameters
and the logging level. In combination with the get_connector
method, it's supposed to set up the
host-to-target connection effortlessly. It supports single connection (default) and multi connection
mode too. Invoke the example scripts with the -h
switch to get more details about the available
options. Custom arguments can be added as documented in the standard argparse.ArgumentParser
class.
All examples in this repo reproduce the behavior of existing C examples from the GSDK. The examples can be tested together with the EFR Connect mobile app. See the documentation of the original C examples to get more information.
- Bluetooth - Empty
- Bluetooth - iBeacon
- Bluetooth - Roaming
- Bluetooth - Thermometer
- Bluetooth - Thermometer Client
- Bluetooth mesh - Empty
To create a custom Bluetooth application, follow these steps:
- Import the util.py module.
- Get a connector instance using the
get_connector
function. - Create your own application class inherited from the
BluetoothApp
class. - Override its
event_handler
method. - Instantiate your application class.
- Call its
run
method.
The example prints a warning message, as follows:
WARNING - BGAPI version mismatch: 3.2.1 (target) != 3.2.2 (host)
The examples are written based on a given BGAPI version. This repo contains a copy of the XAPI descriptor file of this version. The Bluetooth stack running on the NCP Target has its own BGAPI version too. It's the developer's responsibility to keep the BGAPI version on both the target and the host side in sync. Otherwise, the correct behavior cannot be guaranteed.
Difference in the patch version most probably won't cause any issues, while difference in the major version most probably will.
Also note that the pyBGAPI is more sensitive to the API deprecations because, unlike the C implementation of the BGAPI, it has no compatibility layer.
-
Update the Bluetooth SDK in Simplicity Studio and Flash the Bluetooth - NCP demo example on your Wireless Development Kit.
-
Use the XAPI file from the Bluetooth SDK and update your application script accordingly. The XAPI file can be found at /path/to/sdks/gecko_sdk_suite/v3.x/protocol/bluetooth/api/sl_bt.xapi
-
If only the patch versions differ, the warning message can be ignored.
The execution stops after an error message like this is printed:
Received message 'bt_rsp_gattdb_new_session' with parameter(s) 'session' missing.
Command returned 'result' parameter with non-zero errorcode: 0xf
File 'example/bt_empty/app.py', line 65, in gattdb_init
_, session = self.lib.bt.gattdb.new_session()
The error code 0xf
means that the feature is not supported and refers to the Bluetooth dynamic
GATT database feature. Most likely, the root case is that the Bluetooth - NCP Empty example has
been flashed on the target instead of the Bluetooth - NCP. The difference is that the NCP Empty
example contains an almost empty static GATT database, while the NCP contains no static
GATT database at all, but the dynamic GATT database feature instead. The dynamic GATT database
feature makes it possible to configure the GATT database entirely from the host side. The
examples in this repo utilize this feature.
Flash the Bluetooth - NCP example on your development board.
Code after app.run()
call executes only after the app terminates.
The GenericApp class can be executed both in synchronous (blocking) mode and asynchronous (non-blocking) mode. Most examples use the synchronous mode per default.
Use the start
method of the app instead of the run
method. See the following example for a
minimal working code.
import time
from common.util import BluetoothApp, get_device_list
app = BluetoothApp(get_device_list()[0])
app.start()
# Place your custom code here
print("Hello World!")
# Catch KeyboardInterrupt
try:
while True:
time.sleep(60)
except KeyboardInterrupt:
app.stop()