UNPKG

@abandonware/noble

Version:

A Node.js BLE (Bluetooth Low Energy) central library.

322 lines (268 loc) 9.04 kB
const events = require('events'); const util = require('util'); const WebSocket = require('ws'); const NobleBindings = function () { const port = 0xB1e; this._ws = new WebSocket(`ws://localhost:${port}`); this._startScanCommand = null; this._peripherals = {}; 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._onClose.bind(this)); const _this = this; this._ws.on('message', event => { const data = (process.title === 'browser') ? event.data : event; _this.emit('message', JSON.parse(data)); }); }; util.inherits(NobleBindings, events.EventEmitter); NobleBindings.prototype.init = function () { // no-op }; NobleBindings.prototype._onOpen = function () { console.log('on -> open'); }; NobleBindings.prototype._onClose = function () { console.log('on -> close'); this.emit('stateChange', 'poweredOff'); }; NobleBindings.prototype._onMessage = function (event) { let { type, peripheralUuid, address, addressType, connectable, advertisement, rssi, serviceUuids, serviceUuid, includedServiceUuids, characteristics, characteristicUuid, isNotification, state, descriptors, descriptorUuid, handle } = event; const data = event.data ? Buffer.from(event.data, 'hex') : null; if (type === 'stateChange') { console.log(state); this.emit('stateChange', state); } else if (type === 'discover') { advertisement = { localName: advertisement.localName, txPowerLevel: advertisement.txPowerLevel, serviceUuids: advertisement.serviceUuids, manufacturerData: (advertisement.manufacturerData ? Buffer.from(advertisement.manufacturerData, 'hex') : null), serviceData: (advertisement.serviceData ? Buffer.from(advertisement.serviceData, 'hex') : null) }; this._peripherals[peripheralUuid] = { uuid: peripheralUuid, address, advertisement, rssi }; this.emit('discover', peripheralUuid, address, addressType, connectable, advertisement, rssi); } else if (type === 'connect') { this.emit('connect', peripheralUuid); } else if (type === 'disconnect') { this.emit('disconnect', peripheralUuid); } else if (type === 'rssiUpdate') { this.emit('rssiUpdate', peripheralUuid, rssi); } else if (type === 'servicesDiscover') { this.emit('servicesDiscover', peripheralUuid, serviceUuids); } else if (type === 'includedServicesDiscover') { this.emit('includedServicesDiscover', peripheralUuid, serviceUuid, includedServiceUuids); } else if (type === 'characteristicsDiscover') { this.emit('characteristicsDiscover', peripheralUuid, serviceUuid, characteristics); } else if (type === 'read') { this.emit('read', peripheralUuid, serviceUuid, characteristicUuid, data, isNotification); } else if (type === 'write') { this.emit('write', peripheralUuid, serviceUuid, characteristicUuid); } else if (type === 'broadcast') { this.emit('broadcast', peripheralUuid, serviceUuid, characteristicUuid, state); } else if (type === 'notify') { this.emit('notify', peripheralUuid, serviceUuid, characteristicUuid, state); } else if (type === 'descriptorsDiscover') { this.emit('descriptorsDiscover', peripheralUuid, serviceUuid, characteristicUuid, descriptors); } else if (type === 'valueRead') { this.emit('valueRead', peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid, data); } else if (type === 'valueWrite') { this.emit('valueWrite', peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid); } else if (type === 'handleRead') { this.emit('handleRead', peripheralUuid, handle, data); } else if (type === 'handleWrite') { this.emit('handleWrite', peripheralUuid, handle); } else if (type === 'handleNotify') { this.emit('handleNotify', peripheralUuid, handle, data); } }; NobleBindings.prototype._sendCommand = function (command, errorCallback) { const message = JSON.stringify(command); this._ws.send(message, error => { if (error != null) { console.warn('could not send command', command, error); if (typeof errorCallback === 'function') { errorCallback(error); } } }); }; NobleBindings.prototype.startScanning = function (serviceUuids, allowDuplicates) { this._startScanCommand = { action: 'startScanning', serviceUuids, allowDuplicates }; this._sendCommand(this._startScanCommand); this.emit('scanStart'); }; NobleBindings.prototype.stopScanning = function () { this._startScanCommand = null; this._sendCommand({ action: 'stopScanning' }); this.emit('scanStop'); }; NobleBindings.prototype.connect = function (deviceUuid) { const peripheral = this._peripherals[deviceUuid]; this._sendCommand({ action: 'connect', peripheralUuid: peripheral.uuid }); }; NobleBindings.prototype.disconnect = function (deviceUuid) { const peripheral = this._peripherals[deviceUuid]; this._sendCommand({ action: 'disconnect', peripheralUuid: peripheral.uuid }); }; NobleBindings.prototype.updateRssi = function (deviceUuid) { const peripheral = this._peripherals[deviceUuid]; this._sendCommand({ action: 'updateRssi', peripheralUuid: peripheral.uuid }); }; NobleBindings.prototype.discoverServices = function (deviceUuid, uuids) { const peripheral = this._peripherals[deviceUuid]; this._sendCommand({ action: 'discoverServices', peripheralUuid: peripheral.uuid, uuids }); }; NobleBindings.prototype.discoverIncludedServices = function (deviceUuid, serviceUuid, serviceUuids) { const peripheral = this._peripherals[deviceUuid]; this._sendCommand({ action: 'discoverIncludedServices', peripheralUuid: peripheral.uuid, serviceUuid, serviceUuids }); }; NobleBindings.prototype.discoverCharacteristics = function (deviceUuid, serviceUuid, characteristicUuids) { const peripheral = this._peripherals[deviceUuid]; this._sendCommand({ action: 'discoverCharacteristics', peripheralUuid: peripheral.uuid, serviceUuid, characteristicUuids }); }; NobleBindings.prototype.read = function (deviceUuid, serviceUuid, characteristicUuid) { const peripheral = this._peripherals[deviceUuid]; this._sendCommand({ action: 'read', peripheralUuid: peripheral.uuid, serviceUuid, characteristicUuid }); }; NobleBindings.prototype.write = function (deviceUuid, serviceUuid, characteristicUuid, data, withoutResponse) { const peripheral = this._peripherals[deviceUuid]; this._sendCommand({ action: 'write', peripheralUuid: peripheral.uuid, serviceUuid, characteristicUuid, data: data.toString('hex'), withoutResponse }); }; NobleBindings.prototype.broadcast = function (deviceUuid, serviceUuid, characteristicUuid, broadcast) { const peripheral = this._peripherals[deviceUuid]; this._sendCommand({ action: 'broadcast', peripheralUuid: peripheral.uuid, serviceUuid, characteristicUuid, broadcast }); }; NobleBindings.prototype.notify = function (deviceUuid, serviceUuid, characteristicUuid, notify) { const peripheral = this._peripherals[deviceUuid]; this._sendCommand({ action: 'notify', peripheralUuid: peripheral.uuid, serviceUuid, characteristicUuid, notify }); }; NobleBindings.prototype.discoverDescriptors = function (deviceUuid, serviceUuid, characteristicUuid) { const peripheral = this._peripherals[deviceUuid]; this._sendCommand({ action: 'discoverDescriptors', peripheralUuid: peripheral.uuid, serviceUuid, characteristicUuid }); }; NobleBindings.prototype.readValue = function (deviceUuid, serviceUuid, characteristicUuid, descriptorUuid) { const peripheral = this._peripherals[deviceUuid]; this._sendCommand({ action: 'readValue', peripheralUuid: peripheral.uuid, serviceUuid, characteristicUuid, descriptorUuid }); }; NobleBindings.prototype.writeValue = function (deviceUuid, serviceUuid, characteristicUuid, descriptorUuid, data) { const peripheral = this._peripherals[deviceUuid]; this._sendCommand({ action: 'writeValue', peripheralUuid: peripheral.uuid, serviceUuid, characteristicUuid, descriptorUuid, data: data.toString('hex') }); }; NobleBindings.prototype.readHandle = function (deviceUuid, handle) { const peripheral = this._peripherals[deviceUuid]; this._sendCommand({ action: 'readHandle', peripheralUuid: peripheral.uuid, handle }); }; NobleBindings.prototype.writeHandle = function (deviceUuid, handle, data, withoutResponse) { const peripheral = this._peripherals[deviceUuid]; this._sendCommand({ action: 'writeHandle', peripheralUuid: peripheral.uuid, handle, data: data.toString('hex'), withoutResponse }); }; module.exports = NobleBindings;