Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New features: included, secondary services + finer handles control #88

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,26 @@ __Primary Service__
uuid: 'fffffffffffffffffffffffffffffff0', // or 'fff0' for 16-bit
characteristics: [
// see Characteristic for data type
]
],
included: ['secondaryID'], //optional ID of included services - secondary or primary
relativeHandle: 'ff', //optional add 'ff' to handle before adding this service
absoluteHandle: '0f00', //optional start service on '0f00' handle
ID: 'primaryID' //optional ID of this service to be reference in 'included' array
});

__Secondary Service__

var SecondaryService = bleno.SecondaryService;

var secondaryService = new SecondaryService({
uuid: 'fffffffffffffffffffffffffffffff0', // or 'fff0' for 16-bit
characteristics: [
// see Characteristic for data type
],
included: ['moreSecondaryID'], //optional ID of included services - secondary or primary
relativeHandle: 'ff', //optional add 'ff' to handle before adding this service
absoluteHandle: '0f00', //optional start service on '0f00' handle
ID: 'secondaryID' //optional ID of this service to be reference in 'included' array
});

__Characteristic__
Expand All @@ -120,6 +139,8 @@ __Characteristic__
descriptors: [
// see Descriptor for data type
],
relativeHandle: 'ff', //optional add 'ff' to handle before adding this characteristics
relativeValueHandle: 'ff', //optional add 'ff' to handle before adding value attribute of characteristics
onReadRequest: null, // optional read request handler, function(offset, callback) { ... }
onWriteRequest: null, // optional write request handler, function(data, offset, withoutResponse, callback) { ...}
onSubscribe: null, // optional notify subscribe handler, function(maxValueSize, updateValueCallback) { ...}
Expand Down Expand Up @@ -190,7 +211,8 @@ __Descriptor__

var descriptor = new Descriptor({
uuid: '2901',
value: 'value' // static value, must be of type Buffer or string if set
value: 'value', // static value, must be of type Buffer or string if set
relativeHandle: 'ff' //optional add 'ff' to handle before adding this descriptor
});

__Events__
Expand Down
70 changes: 70 additions & 0 deletions examples/include/battery-level-characteristic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
var util = require('util'),
bleno = require('bleno'),
Descriptor = bleno.Descriptor,
Characteristic = bleno.Characteristic;

var BatteryLevelCharacteristic = function() {
BatteryLevelCharacteristic.super_.call(this, {
relativeHandle: '03',
relativeValueHandle: '03',
uuid: '2A19',
properties: ['read','write','writeWithoutResponse','notify'],
descriptors: [
new Descriptor({
relativeHandle: '03',
uuid: '2901',
value: 'Battery level between 0 and 100 percent. A very long description'
}),
new Descriptor({
relativeHandle: '04',
uuid: '2904',
value: new Buffer([0x04, 0x01, 0x27, 0xAD, 0x01, 0x00, 0x00]) // maybe 12 0xC unsigned 8 bit
})
]
});
};

util.inherits(BatteryLevelCharacteristic, Characteristic);

var battery = new Buffer([98]);

BatteryLevelCharacteristic.prototype.onReadRequest = function(offset, callback) {
console.log('Got read',battery);

callback(this.RESULT_SUCCESS, battery);
};

BatteryLevelCharacteristic.prototype.onWriteRequest = function(data, offset, withoutResponse, callback) {
console.log('Got write',data,data.length,offset,withoutResponse);

if (offset !== 0) {
callback(this.RESULT_INVALID_OFFSET);
return
}

if (data.length > 20) {
callback(this.RESULT_INVALID_ATTRIBUTE_LENGTH);
return
}
battery=new Buffer(data);

callback(this.RESULT_SUCCESS);
};

BatteryLevelCharacteristic.prototype.updateValueCallback=null;

BatteryLevelCharacteristic.prototype.onSubscribe = function(maxValueSize, updateValueCallback) {
console.log('Got Subscribe',maxValueSize);
this.updateValueCallback = updateValueCallback;
};

BatteryLevelCharacteristic.prototype.onUnsubscribe = function() {
console.log('Got Unsubscribe');
this.updateValueCallback = null;
};

BatteryLevelCharacteristic.prototype.onNotify = function() {
console.log('Got Notify');
};

module.exports = BatteryLevelCharacteristic;
32 changes: 32 additions & 0 deletions examples/include/battery-secondary-service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
var util = require('util'),
bleno = require('bleno'),
BlenoPrimaryService = bleno.PrimaryService,
BlenoSecondaryService = bleno.SecondaryService,
BatteryLevelCharacteristic = require('./battery-level-characteristic');

function BatterySecondaryServiceA() {
BatterySecondaryServiceA.super_.call(this, {
uuid: '180F',
ID: 'secondaryID',
included: ['secondaryIDB'],
characteristics: [
new BatteryLevelCharacteristic()
],
absoluteHandle: '0030'
});
}

function BatterySecondaryServiceB() {
BatterySecondaryServiceB.super_.call(this, {
uuid: '180E',
ID: 'secondaryIDB',
characteristics: [
new BatteryLevelCharacteristic()
],
absoluteHandle: '0040'
});
}
util.inherits(BatterySecondaryServiceA, BlenoSecondaryService);
util.inherits(BatterySecondaryServiceB, BlenoSecondaryService);
module.exports.a = BatterySecondaryServiceA;
module.exports.b = BatterySecondaryServiceB;
19 changes: 19 additions & 0 deletions examples/include/battery-service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
var util = require('util'),
bleno = require('bleno'),
BlenoPrimaryService = bleno.PrimaryService,
BlenoSecondaryService = bleno.SecondaryService,
BatteryLevelCharacteristic = require('./battery-level-characteristic');

function BatteryService() {
BatteryService.super_.call(this, {
uuid: '180F',
included: ['secondaryID'],
characteristics: [
new BatteryLevelCharacteristic()
],
relativeHandle: '10'
});
}

util.inherits(BatteryService, BlenoPrimaryService);
module.exports = BatteryService;
132 changes: 132 additions & 0 deletions examples/include/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
Object.prototype.isDefined = function(first_argument) {
if (typeof first_argument === 'undefined' || first_argument === null) {
return false;
}
return true;
};

var bleno = require('bleno'),
BatteryService = require('./battery-service'),
BatterySecondaryService = require('./battery-secondary-service');

var primaryService = new BatteryService();
var secondaryServiceA = new BatterySecondaryService.a();
var secondaryServiceB = new BatterySecondaryService.b();

bleno.on('stateChange', function(state) {
console.log('on -> stateChange: ' + state);
if (state === 'poweredOn') {
bleno.startAdvertising('Battery', [primaryService.uuid]);
} else {
bleno.stopAdvertising();
}
});

bleno.on('advertisingStart', function(error) {
console.log('on -> advertisingStart: ' + (error ? 'error ' + error : 'success'));
if (!error) {
bleno.setServices([primaryService, secondaryServiceA, secondaryServiceB]);
}
});

//-----------------------------

var express = require('express');
var app = express();

app.get('/node/:node/value/:value', function (req, res) {
var node = parseInt(req.params.node);
var value =parseInt(req.params.value);

if ({}.isDefined(primaryService.characteristics[node])) {
if ( {}.isDefined(primaryService.characteristics[node].updateValueCallback)) {
primaryService.characteristics[node].updateValueCallback(new Buffer([value]));
}
res.end();
}else{
res.status(404).end();
}
});

var server = app.listen(3000, function () {

var host = server.address().address;
var port = server.address().port;

console.log('Example app listening at http://%s:%s', host, port);

})

//-----------------------------


var attService = [
{'0001': {attType:'2800',attValue:['1800']}}, //0x0001 «Primary Service» «GAP Service»
{'0004': {attType:'2803',attValue:['02','0006','2A00']}}, //0x0004 «Characteristic» {0x02, 0x0006, «Device Name»}
{'0006': {attType:'2A00',attValue:'Example Device'}}, //0x0006 «Device Name» “Example Device”

{'0010': {attType:'2800',attValue:['1801']}}, //0x0010 «Primary Service» «GATT Service»
{'0011': {attType:'2803',attValue:['02','0012','2A05']}}, //0x0011 «Characteristic» {0x02, 0x0012, «Service Changed»}
{'0012': {attType:'2A05',attValue:['00000']}}, //0x0012 «Service Changed» 0x01FF

{'0100': {attType:'2800',attValue:['180F']}}, //0x0100 «Primary Service» «Battery State Service»
{'0106': {attType:'2803',attValue:['02','0110','2A19']}}, //0x0106 «Characteristic» {0x02, 0x0110, «Battery State»}
{'0110': {attType:'2A19',attValue:['04']}}, //0x0110 «Battery State» 0x04

{'0200': {attType:'2800',attValue:['181A']}}, //Environmental Sensing, 0x0200 «Primary Service» «Thermometer Humidity Service»
{'0201': {attType:'2802',attValue:['0500','0504','180A']}},//Device Information 0x0201 «Include» {0x0500, 0x0504, «Manufacturer Service»}
{'0202': {attType:'2802',attValue:['0550','0568']}},//0x0202 «Include» {0x0550,0x0568}
{'0203': {attType:'2803',attValue:['02','0204','2A6E']}}, //0x0203 «Characteristic» {0x02, 0x0203, «Temperature»}
{'0204': {attType:'2A6E',attValue:['028A']}}, //0x0204 «Temperature» 0x028A
{'0205': {attType:'2904',attValue:['0E','FE','272F','01','010C']}},//0x0205 «Characteristic Format» {0x0E, 0xFE, «Celsius», 0x01, «Outside»}
{'0206': {attType:'2901',attValue: 'Outside Temperature' }},//0x0206 «Characteristic UserDescription» “Outside Temperature”

{'0210': {attType:'2803',attValue:['02','0212','2A6F']}}, //0x0210 «Characteristic» {0x02, 0x0212, «Relative Humidity»}
{'0212': {attType:'2A6F',attValue:['27']}}, //0x0212 «Relative Humidity» 0x27
{'0205': {attType:'2904',attValue:['04','00','27AD','01','010C']}},//0x0213 «Characteristic Format» {0x04, 0x00, «Percent», «Bluetooth SIG»,«Outside»}
{'0206': {attType:'2901',attValue: 'Outside Relative Humidity' }},//0x0214 «Characteristic UserDescription» “Outside Relative Humidity”

{'0280': {attType:'2800',attValue:['181D']}}, //0x0280 «Primary Service» «Weight Service» 181D
{'0281': {attType:'2802',attValue:['0505','0509','180A']}},//0x0281 «Include» 0x0505, 0x0509, «Manufacturer Service»}
{'0282': {attType:'2803',attValue:['02','0283','2A9D']}}, //0x0282 «Characteristic» {0x02, 0x0283, «Weight Kg»} 2A9D
{'0283': {attType:'2A9D',attValue:['00005582']}}, //0x0283 «Weight Kg» 0x00005582

{'0300': {attType:'2800',attValue:['1819']}}, //0x030 «Primary Service» «Position Service» 1819
{'0301': {attType:'2803',attValue:['02','0302','2A67']}},//0x0301 «Characteristic» «Location and Speed Characteristic»
{'0302': {attType:'2A67',attValue:['0C', '28BEAFA4', '0B320FCE', '000176']}}, //0x0302 «Characteristic» {mask, longitude, lattitude, elevation} 2A67

{'0400': {attType:'2800',attValue:['1802']}}, //Immediate Alert, 0x0400 «Primary Service» «Alert Service» 1802
{'0401': {attType:'2803',attValue:['02','0402','2A06']}}, //0x0401 «Characteristic» {0x0E, 0x0402, «Alert Enumeration»}
{'0402': {attType:'2A06',attValue:['00']}}, //0x0402 «Alert Enumeration» 0x00

{'0500': {attType:'2801',attValue:['180A']}}, //0x0500 «Secondary Service» «Manufacturer Service» 180A
{'0501': {attType:'2803',attValue:['02','0502','2A29']}}, //0x0501 «Characteristic» {0x02, 0x0502, «Manufacturer Name»} 2A29
{'0502': {attType:'2A29',attValue:'ACME Temperature Sensor'}}, //0x0502 «Manufacturer Name» “ACME Temperature Sensor”
{'0503': {attType:'2803',attValue:['02','0504','2A25']}}, //0x0503 «Characteristic» {0x02, 0x0504, «Serial Number»}
{'0504': {attType:'2A25',attValue:'237495-3282-A'}}, //0x0504 «Serial Number» “237495-3282-A”

{'0505': {attType:'2801',attValue:['180A']}}, //0x0505 «Secondary Service» «Manufacturer Service» 180A
{'0506': {attType:'2803',attValue:['02','0507','2A29']}}, //0x0506 «Characteristic» {0x02, 0x0507, «Manufacturer Name»} 2A29
{'0507': {attType:'2A29',attValue:'ACME Weighing Scales'}}, //0x0507 «Manufacturer Name» “ACME Weighing Scales”
{'0508': {attType:'2803',attValue:['02','0509','2A25']}}, //0x0508 «Characteristic» {0x02, 0x0509, «Serial Number»} 2A25
{'0509': {attType:'2A25',attValue:'11267-2327A00239'}}, //0x0509 «Serial Number» “11267-2327A00239”

{'0550': {attType:'2800',attValue:['feee74dca8de31961149d43596c00a4f']}}, //0x0550 «Secondary Service» «Vendor Specific Service» feee74dca8de31961149d43596c00a4f
{'0560': {attType:'2803',attValue:['02','0568','e9258c1e8962c4b60b452c9018f28880']}}, //0x0560 «Characteristic» {0x02, 0x0568, «Vendor Specific Type»} e9258c1e8962c4b60b452c9018f28880
{'0568': {attType:'e9258c1e8962c4b60b452c9018f28880',attValue:['56656E646F72']}} //0x0568 «Vendor Specific Type» 0x56656E646F72

];
/*
for(var i=0;i < attService.length; i++){
var attVal = attService[i];
if (typeof attVal.attValue === 'string'){
attVal.buffer = new Buffer(attVal.attValue);
}else{
//so array
var len=0;
for(var j=0;j<attVal.attValue.length;j++){
len += attVal.attValue[j].length;
}
console.debug('len=',len,'attVal.attValue=',attVal.attValue);
}
}*/
2 changes: 2 additions & 0 deletions lib/bleno.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ var util = require('util');
var UuidUtil = require('./uuid-util');

var PrimaryService = require('./primary-service');
var SecondaryService = require('./secondary-service');
var Characteristic = require('./characteristic');
var Descriptor = require('./descriptor');

Expand Down Expand Up @@ -41,6 +42,7 @@ function Bleno() {
util.inherits(Bleno, events.EventEmitter);

Bleno.prototype.PrimaryService = PrimaryService;
Bleno.prototype.SecondaryService = SecondaryService;
Bleno.prototype.Characteristic = Characteristic;
Bleno.prototype.Descriptor = Descriptor;

Expand Down
2 changes: 2 additions & 0 deletions lib/characteristic.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ function Characteristic(options) {
this.secure = options.secure || [];
this.value = options.value || null;
this.descriptors = options.descriptors || [];
this.relativeHandle = options.relativeHandle;
this.relativeValueHandle = options.relativeValueHandle;

if (options.onReadRequest) {
this.onReadRequest = options.onReadRequest;
Expand Down
1 change: 1 addition & 0 deletions lib/descriptor.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var UuidUtil = require('./uuid-util');
function Descriptor(options) {
this.uuid = UuidUtil.removeDashes(options.uuid);
this.value = options.value || new Buffer(0);
this.relativeHandle = options.relativeHandle;
}

Descriptor.prototype.toString = function() {
Expand Down
Loading