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

initial websocket bindings #124

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
63 changes: 35 additions & 28 deletions lib/bleno.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ var Characteristic = require('./characteristic');
var Descriptor = require('./descriptor');

var bindings = null;

var platform = os.platform();

if (platform === 'darwin') {
if (process.env.BLENO_WEBSOCKET || process.title === 'browser') {
bindings = require('./websocket/bindings');
} else if (platform === 'darwin') {
bindings = require('./mac/bindings');
} else if (platform === 'linux' || platform === 'win32') {
bindings = require('./hci-socket/bindings');
Expand All @@ -23,6 +24,7 @@ if (platform === 'darwin') {
}

function Bleno() {
this.platform = null;
this.state = 'unknown';
this.address = 'unknown';
this.rssi = 0;
Expand All @@ -38,7 +40,6 @@ function Bleno() {
this._bindings.on('accept', this.onAccept.bind(this));
this._bindings.on('mtuChange', this.onMtuChange.bind(this));
this._bindings.on('disconnect', this.onDisconnect.bind(this));

this._bindings.on('rssiUpdate', this.onRssiUpdate.bind(this));
}

Expand All @@ -51,9 +52,21 @@ Bleno.prototype.Descriptor = Descriptor;
Bleno.prototype.onStateChange = function(state) {
debug('stateChange ' + state);

var self = this;

this.state = state;

this.emit('stateChange', state);
function emit(OSPlatform) {
self.platform = OSPlatform;
self.emit('stateChange', state);
}

if(this.platform){
this.emit('stateChange', state);
}else{
self._bindings.once('OSPlatform', emit);
self._bindings.platform();
}
};

Bleno.prototype.onAddressChange = function(address) {
Expand Down Expand Up @@ -129,23 +142,20 @@ Bleno.prototype.onAdvertisingStart = function(error) {
this.emit('advertisingStart', error);
};

if (platform === 'linux') {
// Linux only API
Bleno.prototype.startAdvertisingWithEIRData = function(advertisementData, scanData, callback) {
if (callback) {
this.once('advertisingStart', callback);
}
this._bindings.startAdvertisingWithEIRData(advertisementData, scanData);
};
} else if (platform === 'darwin' && parseFloat(os.release()) >= 14) {
// OS X >= 10.10 API
Bleno.prototype.startAdvertisingWithEIRData = function(advertisementData, callback) {
if (callback) {
this.once('advertisingStart', callback);
}
this._bindings.startAdvertisingWithEIRData(advertisementData);
};
}
Bleno.prototype.startAdvertisingWithEIRData = function(advertisementData, scanData, callback) {

var _callback = callback;

if(typeof scanData === 'function') {
_callback = scanData;
}

if (_callback) {
this.once('advertisingStart', _callback);
}

this._bindings.startAdvertisingWithEIRData(advertisementData, scanData);
};

Bleno.prototype.stopAdvertising = function(callback) {
if (callback) {
Expand Down Expand Up @@ -176,13 +186,10 @@ Bleno.prototype.onServicesSet = function(error) {
this.emit('servicesSet', error);
};

if (platform === 'linux') {
// Linux only API
Bleno.prototype.disconnect = function() {
debug('disconnect');
this._bindings.disconnect();
};
}
Bleno.prototype.disconnect = function() {
debug('disconnect');
this._bindings.disconnect();
};

Bleno.prototype.updateRssi = function(callback) {
if (callback) {
Expand Down
5 changes: 5 additions & 0 deletions lib/hci-socket/bindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ var debug = require('debug')('bindings');

var events = require('events');
var util = require('util');
var os = require('os');

var AclStream = require('./acl-stream');
var Hci = require('./hci');
Expand Down Expand Up @@ -204,6 +205,10 @@ BlenoBindings.prototype.onExit = function() {
this.disconnect();
};

BlenoBindings.prototype.platform = function(){
this.emit('OSPlatform', os.platform());
}

var blenoBindings = new BlenoBindings();

blenoBindings.init();
Expand Down
12 changes: 8 additions & 4 deletions lib/mac/bindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ BlenoBindings.prototype.sendXpcMessage = function(message) {
this._xpcConnection.sendMessage(message);
};

BlenoBindings.prototype.disconnect = function() {
debug('disconnect is a linux only api');
};

var blenoBindings = new BlenoBindings();

blenoBindings.on('xpcEvent', function(event) {
Expand All @@ -47,10 +51,6 @@ blenoBindings.on('xpcEvent', function(event) {
this.emit('kCBMsgId' + kCBMsgId, kCBMsgArgs);
});

blenoBindings.on('xpcError', function(message) {
console.error('xpcError: ' + message);
});

blenoBindings.sendCBMsg = function(id, args) {
debug('sendCBMsg: ' + id + ', ' + JSON.stringify(args, undefined, 2));
this.sendXpcMessage({
Expand Down Expand Up @@ -88,6 +88,10 @@ blenoBindings.init = function() {
}.bind(this));
};

blenoBindings.platform = function(){
this.emit('OSPlatform', os.platform());
}

blenoBindings.on('kCBMsgId6', function(args) {
var state = ['unknown', 'resetting', 'unsupported', 'unauthorized', 'poweredOff', 'poweredOn'][args.kCBMsgArgState];
debug('state change ' + state);
Expand Down
157 changes: 157 additions & 0 deletions lib/websocket/bindings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
var events = require('events');
var util = require('util');

var debug = require('debug')('bindings');
var WebSocket = require('ws');

var BlenoBindings = function() {
var port = 0xB1f;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arbitrarily chose 0xB1f, one up from nobles websocket.

var ip = process.env.IP || 'localhost';

this._ws = new WebSocket('ws://' + ip + ':' + port);

this._deviceUUID = null;

this.on('message', this._onMessage.bind(this));

if (!this._ws.on) {
this._ws.on = this._ws.addEventListener;
}

this._ws.on('open', this._onOpen.bind(this));
this._ws.on('close', this._onClose.bind(this));
this._ws.on('error', this._onError.bind(this));

var _this = this;
this._ws.on('message', function(event) {
var data = (process.title === 'browser') ? event.data : event;

_this.emit('message', JSON.parse(data));
});
};

util.inherits(BlenoBindings, events.EventEmitter);

BlenoBindings.prototype._onOpen = function() {
};

BlenoBindings.prototype._onClose = function() {
this.emit('stateChange', 'poweredOff');
};

BlenoBindings.prototype._onError = function(error) {
this.emit('xpcError', error);
};

BlenoBindings.prototype._onMessage = function(event) {
var type = event.type;
var state = event.state;
var error = event.error;
var clientAddress = event.clientAddress;
var rssi = event.rssi;
var address = event.address;
var OSPlatform = event.OSPlatform;

debug('on -> message: ' + JSON.stringify(event, undefined, 2));

if (type === 'stateChange') {
debug('state change ' + state);
this.emit('stateChange', state);
} else if (type === 'advertisingStart') {
this.emit('advertisingStart', error);
} else if (type === 'advertisingStartError') {
this.emit('advertisingStartError', error);
} else if (type === 'advertisingStop') {
this.emit('advertisingStop');
} else if (type === 'servicesSet') {
this.emit('servicesSet', error);
} else if (type === 'servicesSetError') {
this.emit('servicesSetError', error);
} else if (type === 'accept') {
this._deviceUUID = clientAddress;
this.emit('accept', clientAddress);
} else if (type === 'disconnect') {
this.emit('disconnect', clientAddress);
} else if (type === 'rssiUpdate') {
this.emit('rssiUpdate', rssi);
} else if (type === 'addressChange') {
this.emit('addressChange', address);
} else if (type === 'OSPlatform'){
this.emit('OSPlatform', OSPlatform);
}
};

BlenoBindings.prototype._sendCommand = function(command) {
debug('on -> sendMessage: ' + JSON.stringify(command, undefined, 2));
var message = JSON.stringify(command);
this._ws.send(message);
};

BlenoBindings.prototype.disconnect = function() {
this._sendCommand({
action: 'disconnect'
});
};

var blenoBindings = new BlenoBindings();

blenoBindings.platform = function(){
this._sendCommand({
action: 'OSPlatform'
});
}

blenoBindings.startAdvertising = function(name, serviceUuids) {
this._sendCommand({
action: 'startAdvertising',
name: name,
serviceUuids: serviceUuids
});
};

blenoBindings.startAdvertisingIBeacon = function(data) {
this._sendCommand({
action: 'startAdvertisingIBeacon',
data: data.toString('hex'),
});
};

blenoBindings.startAdvertisingWithEIRData = function(advertisementData, scanData) {
if(!scanData){
scanData = new Buffer([]);
}

this._sendCommand({
action: 'startAdvertisingWithEIRData',
advertisementData: advertisementData.toString('hex'),
scanData: scanData.toString('hex')
});
};

blenoBindings.stopAdvertising = function() {
this._sendCommand({
action: 'stopAdvertising'
});
};

blenoBindings.setServices = function(services) {
// todo serialize services more fully
this._sendCommand({
action: 'setServices',
services: services
});
};


blenoBindings.updateRssi = function() {
if (this._deviceUUID === null) {
this.emit('rssiUpdate', 127); // not supported
} else {
this._sendCommand({
action: 'updateRssi',
deviceUUID: this._deviceUUID
});
}
};

module.exports = blenoBindings;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"debug": "^2.2.0"
},
"optionalDependencies": {
"ws": "^0.8.0",
"bluetooth-hci-socket": "~0.3.1",
"bplist-parser": "0.0.6",
"xpc-connection": "~0.1.3"
Expand Down
Loading