Developing an nRF52-based remote control for a smart lightbulb (BLE Central)

In any BLE application, there are (at least) two devices involved: a BLE Peripheral device and a BLE Central device.

Usually, the BLE Central is a smartphone, but that doesn’t mean it has to be!

What if:

  • you do not want to have to launch an app everytime you want to control a BLE Peripheral?
  • you want to have a dedicated device that acts as the remote control for the Peripheral device?
  • you want to utilize Bluetooth 5 features such as the long-range feature (Coded PHY)? (which currently does not exist in any smartphone)
  • you want to learn more about how a BLE Central works and how to develop one yourself?

In this case, a dedicated BLE Central device can make a lot more sense than using a smartphone!

Novel Bits blog reader Kevin asks:

I have been looking at many bluetooth 5 blogs and tutorials. Many concentrate on peripheral examples and never provide a central example. Would you please consider writing a simple example for custom project on nrf52840pdk which mirrors and works with your example in ble_lightbulb.zip?

The example (ble_lightbulb.zip) Kevin is referring to is the BLE Lightbulb application example we discussed in my previous tutorial: How to build a smart BLE Lightbulb application using nRF52.

In this blog post, we’ll be going over how to build a remote control device based on the nRF52840 preview development kit provided by Nordic Semiconductor. This development kit will be used to connect to and control the BLE lightbulb application we built in the previous tutorial.

Prerequisites

To follow along with this example, you’ll need to know the basics of BLE. It does not require you to have in-depth knowledge of BLE. In fact, I recommend you do not spend too much time going through the theory and skip right into developing a BLE application and getting your hands dirty once you’ve gone through learning the basics. For this specific post, knowing a little bit more about BLE Central applications will help.

If you’re looking to learn the basics, or simply need a refresher, I recommend checking out my FREE 7-day crash course on the Basics of Bluetooth Low Energy (BLE). Sign up by filling out the form in the bottom right-hand corner of the webpage:

Alternatively, you can sign up at the following link: FREE 7-day crash course on Bluetooth Low Energy (BLE).

So, what hardware & software do I need?

For this tutorial, you’ll need the following:

  • nRF52840 development kit (although any nRF5x development will work, with some modifications)
  • A PC running either Windows, Linux, or macOS (for development)
  • Segger Embedded Studio
  • nRF5 SDK (in our case, we’re using the latest SDK provided by Nordic: nRF5 SDK version 15.0.0)
  • The BLE Lightbulb application we built in the previous tutorial running on another nRF52 development kit

Application Overview

The (BLE Central) application we’ll be developing in this tutorial will cover the following functionality:

  • Scan for the BLE Lightbulb we built in the previous tutorial. It will specifically look for a BLE Peripheral device advertising with the name “BLE_Lightbulb“.
  • During scanning, LED1 on the BLE Central development kit will be ON
  • Once it finds the target BLE device, it will connect to it and discover its services and characteristics looking for two specific ones:
    • LED Service (E54B0001-67F5-479E-8711-B3B99198CE6C)
    • LED2 Characteristic (E54B0002-67F5-479E-8711-B3B99198CE6C)
  • Once connected, LED1 on the BLE Central development kit will be turned OFF and LED2 will be ON
  • Once connected, the user can turn ON and OFF the target BLE Peripheral’s LED2 light by:
    • Pressing Button 1 to turn ON the LED
    • Pressing Button 2 to turn OFF the LED

Getting Started

Installing the SDK (if you haven’t done so already)

We’ve already covered how to install Segger Embedded Studio (the FREE License IDE used for nRF5x development) in a previous post. Here, we’ll focus on the steps that follow the installation.

Next, let’s download the latest nRF5 SDK (version 15.0.0) from Nordic’s website.

Once you have it downloaded, place it in a new folder. To make things easier, we’ll put it in a folder alongside the application we’ll be developing.

In my setup, I’ll be following the structure in the previous tutorial. I’ll be creating a new folder named “ble_lightbulb_remote_control” under the folder “BLE Projects” I created previously.

Figure 1: BLE Projects folder structure

Inside this new folder “ble_lightbulb_remote_control”, I’ll be adding and developing the code for this application.

Here’s what the folder will look like at the end of development:

Figure 2: ble_lightbulb_remote_control folder structure

Anatomy of a BLE Central Application (nRF52)

There are a few basic elements and functionalities that make up a BLE Central in an nRF52 application. These are:

  • Enabling the BLE Central functionality via the macro (defined in sdk_config.h):
  • Enabling the Database Discovery module via the macro (defined in sdk_config.h):

    The Database Discovery module is what handles discovering the GATT Services and Characteristics on a BLE Peripheral device by the BLE Central application.
  • Enabling the number of links for the BLE Central application via the macro (defined in sdk_config.h):

    Based on this count, we also need to update the Total Link Count (also in sdk_config.h):

    In our case, we only need one BLE Central link (no Peripheral links), so we’ll be setting the Total Link Count to 1.
  • A BLE Central Client module that defines the different Services and Characteristics of the target BLE Peripheral device the Central will connect to and interact with. We will be developing this code from scratch in our example.

In addition to enabling these modules, we’ll be using the following generic nRF modules:

Now, let’s go over some of the most important parts of the application!

 

Looking for the source code to this post?
Jump straight to the downloads section at the bottom of this tutorial.

 

LED Service Client

The most important part of our BLE Central application is the Client module that makes the Central aware of the Services and Characteristics of the target BLE Peripheral device. This makes it possible to read and write to the Characteristics of interest as well as subscribe to Notifications and Indications.

For our application, we need to create a Client that understands the LED Service we defined and implemented in our previous LED Lightbulb application tutorial.

We’ll be creating two files: led_service_client.c and led_service_client.h.

Let’s go over the most important sections of each of these source files.

led_service_client.h

  • We need to include the standard nRF header files, but specifically for our Client module, we need to include the “ble_db_discovery.h” header file to be able to utilize the DB Discovery Module needed for discovering GATT Services and Characteristics:
  • Next, we define a macro that we can use to instantiate an instance of the LED Service Client module:

    This follows the method used by many of the examples and SIG-adopted Services in the Nordic nRF5 SDK.
  • Next, we define the UUIDs for the LED Service and the LED2 Characteristic that the BLE Peripheral exposes:
  • Following that, we define the one event we’re interested in: the DB Discovery Complete event. In addition to that, we define a database structure which holds the LED2 Characteristic handle. Finally, we define the LED Event structure that holds all the important information in a BLE event: connection handle, type of event, and the database structure.
  • Define the function prototype for the event handler that the application assigns for this module:
  • The data structure for the main LED Service Client structure:
  • The last data structure we define is responsible for storing the initialization function:
  • Following the data structures, we declare the different functions that the main application will call:
    • Module initialization function:
    • Event handler function:
    • Database discovery event handler:
    • A function for assigning the handles of the discovered LED Service Characteristic(s):
    • Finally, the function that gets used to send a write request to the BLE Peripheral to turn ON or OFF the LED:

led_service_client.c

  • Implementation of the function responsible for handling the Database Discovery event:

    The function looks for the LED Service and the LED2 Characteristic that’s contained within it. This is necessary since we need to store the handle that gets referenced whenever we need to read or write a value to the LED2 Characteristic.
  • Implementation of the initialization function for the LED Service Client module:

    The most important aspect of this function is that it registers the LED Service UUID
  • Implementation of the function that handles the BLE events within the LED Service Client module:

    This function handles both the disconnection event as well as the Write Response event (in response to a Write Request).
  • Implementation of the function that handles sending the Write Request to turn LED2 On or Off:

    Notice it utilizes the LED2 Characteristic handle we stored after the Database Discovery is complete.
  • Finally, the function that assigns any handles of interest:

The last file we’ll look at is the main application source file: main.c:

main.c

We won’t cover the whole file, but rather focus on the most important sections.

In the following code section, we instantiate:

  • the LED Service Client module
  • the GATT module
  • the Database Discovery module

Next, we define the Advertised name of the target BLE Peripheral device:

Another important function we need to define is the function for scanning of BLE Peripheral devices:

In this function, we also toggle the BLE Central development kit’s LEDs indicate the current state: Scanning.

The following function initializes the LED Service Client module:

The following function is the event handler that gets assigned to the LED Service Client module during initialization:

It handles the Database Discovery event and assigns the handles.

In the following function, we parse the Advertising Report returned by the stack and look for the target device:

If we discover the target BLE Peripheral device (our Lightbulb Peripheral), we initiate a connection to the device.

In the BLE event handler function, we start the Database (GATT) Discovery process if we detect that we’re connected:

Also, notice that we set the development kit’s LEDs to the Connected state (instead of the Scanning state).

Next, we need to initialize the development kit’s buttons so we can detect when a button (Button 1 or Button 2) is pressed:

We initialized the buttons, but we also need a function to handle the specific button press. Based on that, we set the appropriate setting for LED2 (On or Off) on the BLE Peripheral development kit:

Finally, in main(), we initialize all the necessary modules and start the Scanning process:

Testing

Now that we’ve developed the code for the BLE Central device, we will test it and make sure it works correctly.

To do this, we will flash the BLE Central to one nRF52840 development kit and the BLE Peripheral application to another nRF52840 development kit (explained in the previous tutorial).

To make it easier to follow, I’ve recorded a video explaining the different aspects of the system as well as testing its functionality.

Watch the video here:

Summary

To summarize, in this tutorial:

  • We went over the main application’s functionality
  • We went over the most important elements within an nRF52-based BLE Central application
  • We described the structure of the Segger Embedded Studio project and its source files
  • We implemented the LED Service Client module which is needed for discovering and interfacing with the BLE Peripheral’s LED Service and LED2 Characteristic
  • We went over the most important code sections in the BLE Central “Remote Control” application
  • We tested the application to make sure it is working correctly

To be notified when future tutorials are published here, be sure to enter your email address in the form below!

If you would like to download the code used in this post, please enter your email address in the form below. You’ll get a .zip containing all the source code, and I will also send you a FREE 9-page Report on the Essential Bluetooth Developer Tools. In addition to that, you will receive exclusive content, tips, and tricks that I don’t post to the blog!

By | 2018-06-20T13:08:25+00:00 June 5th, 2018|Categories: BLE technology, Tutorials|Tags: , , , , , , |4 Comments

About the Author:

Mohammad Afaneh
Mohammad has a strong passion for developing Bluetooth Low Energy and IoT applications. He helps developers develop for BLE faster through detailed technical tutorials, articles, and videos. He enjoys playing sports, spending time with his wife and kids, and reading non-fiction books. Connect with him on LinkedIn at https://www.linkedin.com/in/mafaneh.

4 Comments

  1. Kevin Gordon June 5, 2018 at 6:05 pm - Reply

    Thank you Mohammad. This is an excellent tutorial for a central example. Now we can test with nrf52-dk to nrf52-dk or nrf52840-pdk to nrf52840-pdk. Many thanks, Kevin.

  2. Giannis Asimakides June 10, 2018 at 3:16 am - Reply

    Well don presentation! We want to see more on these tutorials and especiall on power train applications.

    • Mohammad Afaneh
      Mohammad Afaneh June 10, 2018 at 7:41 pm - Reply

      Thanks, Giannis.

      Can you elaborate on the types of applications you’re referring to?

Leave A Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.