Author: Johan Hedberg
The Bluetooth Mesh specification was announced to the public in July 2017, and now, thanks to the contributions from Intel Corporation, the Zephyr project has an implementation of it. The code is available in the upstream master branch, and will be part of the Zephyr OS 1.9 release, due early September 2017.
The public API for Bluetooth Mesh can be found in here.
Bluetooth Mesh Overview
Bluetooth Mesh is a new standard that opens a whole new wave of low-power wireless use cases. It extends the range of communication from a single peer-to-peer connection to a true mesh topology covering large areas, such as an entire building. This paves the way for both home and industrial automation applications. Typical home scenarios include things like controlling the lights in your apartment or adjusting the thermostat. Although Bluetooth 5 was released end of last year, Bluetooth Mesh can be implemented on any device supporting Bluetooth 4.0 or later. This means that we'll likely see very rapid market adoption of the technology.
The specification itself can be found here.
Bluetooth Mesh Implementation in the Zephyr Project
The Zephyr OS implementation covers all layers and most optional features of the Bluetooth Mesh stack. The following is a list of some of these features and the c-files where the implementation can be found:
- GATT & Advertising bearers (proxy.c & adv.c)
- Network Layer (net.c)
- Lower and Upper Transport Layers (transport.c)
- Access Layer (access.c)
- Foundation Models, Server role (health.c & cfg.c)
- Both PB-ADV and PB-GATT based provisioning (prov.c)
- Low Power Node support (lpn.c)
- Relay support (net.c)
- GATT Proxy (proxy.c)
Some notable features that are not yet part of the implementation:
- Friend support (initial bits are already in place in friend.c)
- Provisioner support (low-value for typical Zephyr devices)
- Foundation Client models (low-value for typical Zephyr devices)
- GATT Client (low-value for typical Zephyr devices)
We hope to see some of the missing features in future releases, and in particular Friend support.
Provisioning with the Zephyr OS
In order to make a Zephyr OS-based device a functional mesh node, it needs to be provisioned with network security keys as well as a unique unicast address. Since the Zephyr OS can't (currently) act as a Provisioner for other devices, a non-Zephyr OS based implementation must be used for this. For prototyping purposes, it is possible to hard-code the address and keys in your application - an example for how to do this can be seen in the mesh_demo sample.
In practice the following options are therefore available for provisioning and configuring Zephyr OS based devices:
- Self-provisioning (only for prototyping, not product-level usage)
- Silicon Labs Android Mesh application
- Bluetooth PTS (used for specification conformance testing)
- BlueZ meshctl tool. Will be part of the next BlueZ release (BlueZ 5.47).
Integrating Bluetooth Mesh using the Zephyr OS
A mesh network consists of a fairly elaborate hierarchy of concepts. Each device participating in a network is called a node. Each node consists of one or more elements, which are the uniquely addressable entities in a mesh network. Each element in turn has a set of so called models, either standard ones or vendor specified ones.
In essence, a model defines certain states and behavior which can be influenced by sending or receiving messages. The Mesh Profile Specification includes a few so-called Foundation models, which every mesh node must support.
The Zephyr project provides an existing implementation for these, so there's very little that an application writer needs to do about them. What remains for the application writer is then to either choose to implement suitable standard models (found in the mesh model Specification) or create custom vendor models in case the standard ones are not suitable.
In the Zephyr Project, a model is defined using the BT_MESH_MODEL() macro. The application provides as parameters: a model identifier, an array of message handlers, a message publication context, and optional user data to pass to the message handlers. The model in turn is included in an array of other models, which together form an element. To initialize mesh support, an application gives the bt_mesh_init() API call the device composition (mainly an array of elements) as well as basic provisioning capability information.
For inserting the foundation models where required (e.g. on the primary element) the application would use either BT_MESH_MODEL_CFG_SRV() or
BT_MESH_MODEL_HEALTH_SRV() instead of BT_MESH_MODEL().