While waiting for my flic.io buttons to turn up I’ve been playing with building my own Bluetooth Low Energy devices.
Since I already had a couple of sensors hooked up to publish their values via MQTT I thought I would try and build a bridge between MQTT and BLE.
I’m using a Raspberry Pi, a Bluetooth 4.0 USB dongle and a NodeJS npm module called bleno.
It turned out to be petty easy, first a short file to set up the BLE service and connect to MQTT:
var util = require('util'); var bleno = require('bleno'); var mqtt = require('mqtt'); var BlenoPrimarySerivce = bleno.PrimaryService; var TopicCharacteristic = require('./topicCharacteristic'); var config = require("./config"); var client = mqtt.connect(config.broker); var topicCharacteristic = new TopicCharacteristic(config); client.on('connect', function(){ client.subscribe(config.topic); }); client.on('message',function(topic, message){ topicCharacteristic.update(message); }); bleno.on('stateChange', function(state){ if (state === 'poweredOn') { bleno.startAdvertising('mqtt', ['ba42561bb1d2440a8d040cefb43faece']); } else { bleno.stopAdvertising(); } }); bleno.on('advertisingStart', function(error){ if(!error) { bleno.setServices([ new BlenoPrimarySerivce({ uuid: 'ba42561bb1d2440a8d040cefb43faece', characteristics: [ topicCharacteristic ] }) ]); } });
And then something to add the characteristic for the topic:
var util = require('util'); var bleno = require('bleno'); function TopicCharacteristic(config, client) { bleno.Characteristic.call(this, { uuid: '6bcb06e2747542a9a62a54a1f3ce11e6', properties: ['read', 'write', 'notify'], descriptors: [ new bleno.Descriptor({ uuid: '2901', value: 'Topic: ' + config.topic }) ] }); this._value = new Buffer(0); this._updateValueCallback = null; this._client = client; this._topic = config.topic; } util.inherits(TopicCharacteristic, bleno.Characteristic); TopicCharacteristic.prototype.onWriteRequest = function(data, offset, withoutResponse, callback) { this._value = data; client.publish(this._topic, data); callback(this.RESULT_SUCCESS); } TopicCharacteristic.prototype.onReadRequest = function(offset, callback) { callback(this.RESULT_SUCCESS, this._value); } TopicCharacteristic.prototype.onSubscribe = function(maxValueSize, updateValueCallback) { this._updateValueCallback = updateValueCallback; } TopicCharacteristic.prototype.onUnsubscribe = function () { this._updateValueCallback = null; } TopicCharacteristic.prototype.update = function(value) { this._value = value; if (this._updateValueCallback) { this._updateValueCallback(this._value); } } module.exports = TopicCharacteristic;
I’ve used 2 randomly generated UUIDs, one for the service and one for the characteristic.
The code should allow you to read the last value published, publish a new value and subscribe to notifications when new values arrive.
I pulled together a quick Android app to subscribe to the notifications and update when a new value is published and it seams to be working well.
The code is all up on Github and on npmjs so feel free to have a play.
You can test it with the Bluez gatttoool.
[hardillb@bagend ~]$ gatttool -b 00:1A:7D:DA:71:15 -I [00:1A:7D:DA:71:15][LE]> connect Attempting to connect to 00:1A:7D:DA:71:15 Connection successful [00:1A:7D:DA:71:15][LE]> primary attr handle: 0x0001, end grp handle: 0x0005 uuid: 00001800-0000-1000-8000-00805f9b34fb attr handle: 0x0006, end grp handle: 0x0009 uuid: 00001801-0000-1000-8000-00805f9b34fb attr handle: 0x000a, end grp handle: 0x000e uuid: ba42561b-b1d2-440a-8d04-0cefb43faece [00:1A:7D:DA:71:15][LE]> characteristics handle: 0x0002, char properties: 0x02, char value handle: 0x0003, uuid: 00002a00-0000-1000-8000-00805f9b34fb handle: 0x0004, char properties: 0x02, char value handle: 0x0005, uuid: 00002a01-0000-1000-8000-00805f9b34fb handle: 0x0007, char properties: 0x20, char value handle: 0x0008, uuid: 00002a05-0000-1000-8000-00805f9b34fb handle: 0x000b, char properties: 0x1a, char value handle: 0x000c, uuid: 6bcb06e2-7475-42a9-a62a-54a1f3ce11e6 [00:1A:7D:DA:71:15][LE]> char-write-req 0x000d 0300 Characteristic value was written successfully Notification handle = 0x000c value: 42 61 72 Notification handle = 0x000c value: 48 65 6c 6c 6f 57 6f 72 6c 64 Notification handle = 0x000c value: 54 65 73 74 69 6e 67 20 31 32 33 [00:1A:7D:DA:71:15][LE]> [00:1A:7D:DA:71:15][LE]> quit
The lines that start Notification handle contain the bytes published, in this case
- Bar
- HelloWorld
- Testing 123
Nice work. If I understand correctly, you create a “peripheral” device so you can connect from a central (“android”).
Do you know if it could work the other way – Rpi to be a central and to forward to mqtt broker? Something like ble-to-mqtt bridge?
The idea is to easily integrate simple “peripherals” (sensors, buttons, etc.) in the cloud.
Writing code to read a BLE endpoint and publish to MQTT is a relatively trivial task done regularly, if you want to do it with NodeJS then look at the noble module.