UNPKG

gatt-ip-js

Version:

GATT-IP library is A simple javascript protocol to connect any Bluetooth Smart (GATT) Device to the IP network

286 lines (255 loc) 10.8 kB
var C = require('./lib/constants').C; var helper = require('./lib/message-helper'); var Peripheral = require('./peripheral').Peripheral; var Stream = require('./stream').Stream; var InternalError = require('./errors').InternalError; var ApplicationError = require('./errors').ApplicationError; var ee = require("./lib/event-emitter"); var GatewayError = require("./errors").GatewayError; function Gateway(gattip, scanFilters) { ee.instantiateEmitter(this); var self = this; var peripherals = {}; var objectsByObjectId = {}; this.isScanning = false; this.isPoweredOn = function () { return self.state == C.kPoweredOn; }; // REQUESTS ================================================= this._authenticate = function (callback, token, version) { var params = {}; params[C.kDeviceAccessToken] = token; params[C.kGetVersionInfo] = version; gattip.request(C.kOpen, params, callback, function (params) { if (params && params.isAuthenticated === false) { gattip.reject(callback, new GatewayError("Authentication failed")) } else { gattip.fulfill(callback, self); } }); }; this.scan = function (callback, scanOptions) { var params = {}; if (scanOptions) { if ('boolean' == typeof scanOptions.scanDuplicates) { params[C.kScanOptionAllowDuplicatesKey] = scanOptions.scanDuplicates; } if ('object' == typeof scanOptions.services) { params[C.kServiceUUIDs] = scanOptions.services; } } gattip.request(C.kScanForPeripherals, params, callback, function (params) { self.isScanning = true; gattip.fulfill(callback, self); }); }; // TODO: Unregister all on scan event handlers this.stopScan = function (callback) { gattip.request(C.kStopScanning, {}, callback, function (params) { self.isScanning = false; gattip.fulfill(callback, self); }); }; this.centralState = function (callback) { var params = {}; gattip.request(C.kCentralState, {}, callback, function (params) { self.state = params[C.kState]; gattip.fulfill(callback, self); }); }; this.configure = function (callback, pwrAlert, centralID) { var params = {}; if (typeof pwrAlert != 'undefined') { params[C.kShowPowerAlert] = pwrAlert; } if (typeof centralID != 'undefined') { params[C.kIdentifierKey] = centralID; } gattip.request(C.kConfigure, {}, callback, function (params) { gattip.fulfill(callback, self); }); }; this.openStream = function (callback, streamPath, options) { var params = {}; if (!options) { options = {}; } if (typeof options.speed == 'number') { params[C.kSpeed] = options.speed; } if (typeof options.force == 'boolean') { params[C.kForce] = options.force; } var streamObjectId = params[C.kObjectId] = streamPath; helper.requireFields('objectId', params, [C.kObjectId]); gattip.request(C.kOpenStream, params, callback, function (params) { if (typeof params[C.kObjectId] == "string") { // if the response contains a new object ID, replace it streamObjectId = params[C.kObjectId]; } var stream = new Stream(this, streamObjectId); objectsByObjectId[streamObjectId] = stream; gattip.fulfill(callback, stream); }); }; // this.closeStream = function (callback, objectId) { var params = {}; var streamObjectId = params[C.kObjectId] = objectId; helper.requireFields('objectId', params, [C.kObjectId]); gattip.request(C.kCloseStream, params, callback, function (params) { var stream = objectsByObjectId[streamObjectId]; delete objectsByObjectId[streamObjectId]; gattip.fulfill(callback, stream); }); }; // this.handleScanIndication = function(params) { var peripheralUUID = params[C.kPeripheralUUID]; if (!peripheralUUID) { throw new InternalError('Peripheral UUID is not availabvle'); } if (scanFilters && scanFilters.uuids) { for (var i = 0; i < scanFilters.uuids.length; i++) { var uuid = scanFilters.uuids[i]; if (uuid && uuid.length) { if (uuid != peripheralUUID) { return; } } } } var peripheral = self.getPeripheral(peripheralUUID); if (!peripheral) { peripheral = self.addPeripheral(new Peripheral( gattip, peripheralUUID, params[C.kPeripheralName], params[C.kRSSIkey], params[C.kCBAdvertisementDataTxPowerLevel], params[C.kCBAdvertisementDataIsConnectable], params[C.kCBAdvertisementDataServiceUUIDsKey], params[C.kCBAdvertisementDataManufacturerDataKey], params[C.kCBAdvertisementDataServiceDataKey], params[C.kAdvertisementDataKey], params[C.kScanRecord]) ); } else { peripheral._updateFromScanData( params[C.kPeripheralName], params[C.kRSSIkey], params[C.kCBAdvertisementDataTxPowerLevel], params[C.kCBAdvertisementDataIsConnectable], params[C.kCBAdvertisementDataServiceUUIDsKey], params[C.kCBAdvertisementDataManufacturerDataKey], params[C.kCBAdvertisementDataServiceDataKey], params[C.kAdvertisementDataKey], params[C.kScanRecord] ); } self.emit('scan', peripheral); }; // PERIPHERAL MANAGEMENT ETC. ====================================== this.addPeripheralWithValues = function (uuid, name, RSSI, txPwr, serviceUUIDs, mfrData, scvData, connectable) { if (!uuid) { throw new InternalError('Attempting to add an empty peripheral'); } var peripheral = self.addPeripheral(new Peripheral(gattip, uuid, name, RSSI, txPwr, connectable, serviceUUIDs, mfrData, scvData)); peripherals[uuid] = peripheral; return peripheral; }; this.addPeripheral = function (peripheral) { if (!peripheral || !peripheral.uuid) { throw new InternalError('Attempting to add an empty peripheral'); } peripherals[peripheral.uuid] = peripheral; return peripheral; }; this.addStream = function (objectId) { var stream =new Stream(this, objectId); objectsByObjectId[objectId] = stream; return stream; }; this.removePeripheral = function (peripheral) { if (!peripheral || !peripheral.uuid) { throw new InternalError('Attempting to remove an empty peripheral'); } delete peripherals[peripheral.uuid]; }; this.getPeripheral = function (peripheralUUID) { return peripherals[peripheralUUID]; }; this.getObject = function (objectId) { return objectsByObjectId[objectId]; }; this.removeObject = function (objectId) { delete objectsByObjectId[objectId]; }; this.getPeripheralOrDie = function (peripheralUUID) { var peripheral = peripherals[peripheralUUID]; if (!peripheral) { throw new InternalError('Unable to find peripheral with UUID ' + peripheralUUID); } return peripheral; }; this.getObjects = function(type, peripheralUUID, serviceUUID, characteristicUUID, descriptorUUID) { var resultObj = {}; resultObj.peripheral = peripherals[peripheralUUID]; if (resultObj.peripheral) { if (type === 'p') { return resultObj; } resultObj.service = resultObj.peripheral.findService(serviceUUID); if (resultObj.service) { if (type === 's') { return resultObj; } resultObj.characteristic = resultObj.service.findCharacteristic(characteristicUUID); if (resultObj.characteristic) { if (type === 'c') { return resultObj; } resultObj.descriptor = resultObj.characteristic.findDescriptor(descriptorUUID); if (resultObj.descriptor) { if (type === 'd') { return resultObj; } else { throw new InternalError('_getObjects: Argument "type" is required'); } } else { throw new ApplicationError('Descriptor "'+ descriptorUUID + '" not found in the service table'); } } else { throw new ApplicationError('Characteristic "'+ characteristicUUID + '" not found in the service table'); } } else { throw new ApplicationError('Service "'+ serviceUUID + '" not found in the service table'); } } else { throw new ApplicationError('Peripheral with id '+ peripheralUUID + ' not found'); } }; this.getObjectsFromMessage = function(type, params) { if (!params) { throw new InternalError("Message parameters are missing"); } try { return self.getObjects(type, params[C.kPeripheralUUID], params[C.kServiceUUID], params[C.kCharacteristicUUID], params[C.kDescriptorUUID] ); } catch (error) { throw new InternalError(error.message, error.detail); } }; this.close = function () { for (var pIdx in Object.keys(peripherals)) { if (peripherals.hasOwnProperty(pIdx)) { var p = peripherals[pIdx]; p.removeAllListeners(); p.removeAllChildListenersAndFlush(); } } peripherals = {}; self.removeAllListeners(); }; } ee.makeEmitter(Gateway); module.exports.Gateway = Gateway;