Bluetooth with Raspberry Pi and bleno – part 3: notifications

22.01.2018

Marcin Budny
Head of R&D
Marcin Budny
Architect and developer, over 10 years in IT. He works with intelligent transport systems, researches new technology and explores ways to apply it. Passionate about building software, always looking to learn something new. Focused on .NET, yet curious about the rest of the dev world.
 

This post is a continuation of the series on Bluetooth with bleno.

Bluetooth with Raspberry Pi and bleno – part 1: iBeacon

Bluetooth with Raspberry Pi and bleno – part 2: GATT

In this post I’ll show how to send notifications to a connected client.

Notifications

Sometimes it is useful to push information to a connected client instead of waiting for it to pull it. An example could be a heartbeat monitor that pushes information about the reading after each detected change. Fortunately, GATT provides us with a way to implement such scenario. A characteristic may support notifyaccess mode, so that a client can subscribe to it.

Counter

I’ll use a simple counter as an example in this post. The counter will increase it’s value once per second. The client will be able to subscribe to it and observe the values as they change.

Let’s start with some UUIDs.

const COUNTER_SERVICE_UUID = "00010000-9FAB-43C8-9231-40F6E305F96D";
const COUNTER_CHAR_UUID = "00010001-9FAB-43C8-9231-40F6E305F96D";

Next step is to declare the counter characteristic:

class CounterCharacteristic extends bleno.Characteristic {
    constructor() {
        super({
            uuid: COUNTER_CHAR_UUID,
            properties: ["notify"],
            value: null
        });

        this.counter = 0;
    }

    onSubscribe(maxValueSize, updateValueCallback) {
        console.log(`Counter subscribed, max value size is ${maxValueSize}`);
        this.updateValueCallback = updateValueCallback;
    }

    onUnsubscribe() {
        console.log("Counter unsubscribed");
        this.updateValueCallback = null;
    }    

    sendNotification(value) {
        if(this.updateValueCallback) {
            console.log(`Sending notification with value ${value}`);

            const notificationBytes = new Buffer(2);
            notificationBytes.writeInt16LE(value);

            this.updateValueCallback(notificationBytes);
        }
    }

    start() {
        console.log("Starting counter");
        this.handle = setInterval(() => {
            this.counter = (this.counter + 1) % 0xFFFF;
            this.sendNotification(this.counter);
        }, 1000);
    }

    stop() {
        console.log("Stopping counter");
        clearInterval(this.handle);
        this.handle = null;
    }
}

There are two methods: onSubscribeand onUnsubscribe, which will be called when a client subscribes or unsubscribes from the characteristic. The former gives us opportunity to store a callback, that will be later used to notify the client about changes in the data. The sendNotificationmethod is called from the timer and makes use of the callback.

To start the peripheral:

let counter = new CounterCharacteristic();
counter.start();


bleno.on("stateChange", state => {

    if (state === "poweredOn") {
        
        bleno.startAdvertising("Counter", [COUNTER_SERVICE_UUID], err => {
            if (err) console.log(err);
        });

    } else {
        console.log("Stopping...");
        counter.stop();
        bleno.stopAdvertising();
    }        
});

bleno.on("advertisingStart", err => {

    console.log("Configuring services...");
    
    if(err) {
        console.error(err);
        return;
    }

    let service = new bleno.PrimaryService({
        uuid: COUNTER_CHAR_UUID,
        characteristics: [counter]
    });

    bleno.setServices([service], err => {
        if(err)
            console.log(err);
        else
            console.log("Services configured");
    });
});

Again, we can use the generic client app to connect to the device and see the result.

You can find full source code for the sample application here.

Summary

This short post explains how to deal with notifications initiated by the peripheral Bluetooth device. In the upcoming posts, we’ll show how to connect and communicate with peripheral devices from mobile apps.