@stoprocent/noble 1.19.1 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/README.md +393 -650
  2. package/examples/advertisement-discovery.js +57 -48
  3. package/examples/connect-address.js +59 -34
  4. package/examples/echo.js +59 -69
  5. package/examples/enter-exit.js +55 -49
  6. package/examples/multiple-bindings.js +53 -0
  7. package/examples/peripheral-explorer-async.js +39 -21
  8. package/examples/peripheral-explorer.ts +52 -0
  9. package/index.d.ts +249 -209
  10. package/index.js +4 -1
  11. package/jest.config.js +4 -0
  12. package/lib/characteristic.js +153 -127
  13. package/lib/{win/src/callbacks.h → common/include/Emit.h} +17 -14
  14. package/lib/common/include/Peripheral.h +31 -0
  15. package/lib/common/include/ThreadSafeCallback.h +95 -0
  16. package/lib/{win/src/callbacks.cc → common/src/Emit.cc} +111 -68
  17. package/lib/descriptor.js +57 -54
  18. package/lib/hci-socket/acl-stream.js +2 -4
  19. package/lib/hci-socket/bindings.js +96 -73
  20. package/lib/hci-socket/gap.js +2 -3
  21. package/lib/hci-socket/gatt.js +2 -5
  22. package/lib/hci-socket/hci.js +19 -7
  23. package/lib/hci-socket/signaling.js +2 -3
  24. package/lib/hci-socket/smp.js +2 -3
  25. package/lib/hci-socket/vs.js +1 -0
  26. package/lib/mac/binding.gyp +5 -7
  27. package/lib/mac/bindings.js +1 -3
  28. package/lib/mac/src/ble_manager.h +1 -8
  29. package/lib/mac/src/ble_manager.mm +87 -44
  30. package/lib/mac/src/napi_objc.h +1 -0
  31. package/lib/mac/src/napi_objc.mm +0 -6
  32. package/lib/mac/src/noble_mac.h +5 -3
  33. package/lib/mac/src/noble_mac.mm +99 -57
  34. package/lib/mac/src/objc_cpp.h +3 -2
  35. package/lib/mac/src/objc_cpp.mm +0 -6
  36. package/lib/noble.js +583 -488
  37. package/lib/peripheral.js +171 -174
  38. package/lib/resolve-bindings.js +37 -30
  39. package/lib/service.js +58 -55
  40. package/lib/win/binding.gyp +4 -11
  41. package/lib/win/bindings.js +1 -3
  42. package/lib/win/src/ble_manager.cc +291 -166
  43. package/lib/win/src/ble_manager.h +11 -13
  44. package/lib/win/src/napi_winrt.cc +1 -7
  45. package/lib/win/src/napi_winrt.h +1 -1
  46. package/lib/win/src/noble_winrt.cc +88 -61
  47. package/lib/win/src/noble_winrt.h +5 -3
  48. package/lib/win/src/notify_map.cc +0 -7
  49. package/lib/win/src/notify_map.h +1 -8
  50. package/lib/win/src/peripheral_winrt.cc +29 -11
  51. package/lib/win/src/peripheral_winrt.h +1 -1
  52. package/lib/win/src/radio_watcher.cc +79 -69
  53. package/lib/win/src/radio_watcher.h +30 -11
  54. package/lib/win/src/winrt_cpp.cc +1 -1
  55. package/lib/win/src/winrt_cpp.h +3 -0
  56. package/package.json +14 -17
  57. package/prebuilds/darwin-x64+arm64/@stoprocent+noble.node +0 -0
  58. package/prebuilds/win32-ia32/@stoprocent+noble.node +0 -0
  59. package/prebuilds/win32-x64/@stoprocent+noble.node +0 -0
  60. package/test/lib/characteristic.test.js +202 -322
  61. package/test/lib/descriptor.test.js +62 -95
  62. package/test/lib/hci-socket/acl-stream.test.js +112 -108
  63. package/test/lib/hci-socket/bindings.test.js +576 -365
  64. package/test/lib/hci-socket/hci.test.js +442 -473
  65. package/test/lib/hci-socket/signaling.test.js +45 -48
  66. package/test/lib/hci-socket/smp.test.js +144 -142
  67. package/test/lib/hci-socket/vs.test.js +193 -18
  68. package/test/lib/peripheral.test.js +492 -322
  69. package/test/lib/resolve-bindings.test.js +207 -82
  70. package/test/lib/service.test.js +79 -88
  71. package/test/noble.test.js +426 -1088
  72. package/.editorconfig +0 -11
  73. package/.nycrc.json +0 -4
  74. package/codecov.yml +0 -5
  75. package/examples/cache-gatt-discovery.js +0 -198
  76. package/examples/cache-gatt-reconnect.js +0 -164
  77. package/examples/ext-advertisement-discovery.js +0 -65
  78. package/examples/peripheral-explorer.js +0 -225
  79. package/examples/pizza/central.js +0 -194
  80. package/examples/pizza/pizza.js +0 -60
  81. package/examples/test/test.custom.js +0 -131
  82. package/examples/uart-bind-params.js +0 -28
  83. package/lib/distributed/bindings.js +0 -326
  84. package/lib/mac/src/callbacks.cc +0 -222
  85. package/lib/mac/src/callbacks.h +0 -84
  86. package/lib/mac/src/peripheral.h +0 -23
  87. package/lib/resolve-bindings-web.js +0 -9
  88. package/lib/webbluetooth/bindings.js +0 -368
  89. package/lib/websocket/bindings.js +0 -321
  90. package/lib/win/src/peripheral.h +0 -23
  91. package/test/lib/distributed/bindings.test.js +0 -918
  92. package/test/lib/webbluetooth/bindings.test.js +0 -190
  93. package/test/lib/websocket/bindings.test.js +0 -456
  94. package/test/mocha.setup.js +0 -0
  95. package/with-bindings.js +0 -5
  96. package/with-custom-binding.js +0 -6
  97. package/ws-slave.js +0 -404
package/lib/noble.js CHANGED
@@ -1,659 +1,754 @@
1
1
  const debug = require('debug')('noble');
2
2
 
3
- const events = require('events');
4
- const util = require('util');
3
+ const { EventEmitter } = require('events');
5
4
 
6
5
  const Peripheral = require('./peripheral');
7
6
  const Service = require('./service');
8
7
  const Characteristic = require('./characteristic');
9
8
  const Descriptor = require('./descriptor');
10
9
 
11
- function Noble (bindings) {
12
- this.initialized = false;
13
-
14
- this.address = 'unknown';
15
- this._state = 'unknown';
16
- this._bindings = bindings;
10
+ class Noble extends EventEmitter {
17
11
 
18
- this._cleanupPeriperals();
19
-
20
- this._bindings.on('stateChange', this.onStateChange.bind(this));
21
- this._bindings.on('addressChange', this.onAddressChange.bind(this));
22
- this._bindings.on('scanParametersSet', this.onScanParametersSet.bind(this));
23
- this._bindings.on('scanStart', this.onScanStart.bind(this));
24
- this._bindings.on('scanStop', this.onScanStop.bind(this));
25
- this._bindings.on('discover', this.onDiscover.bind(this));
26
- this._bindings.on('connect', this.onConnect.bind(this));
27
- this._bindings.on('disconnect', this.onDisconnect.bind(this));
28
- this._bindings.on('rssiUpdate', this.onRssiUpdate.bind(this));
29
- this._bindings.on('servicesDiscover', this.onServicesDiscover.bind(this));
30
- this._bindings.on('servicesDiscovered', this.onServicesDiscovered.bind(this));
31
- this._bindings.on('includedServicesDiscover', this.onIncludedServicesDiscover.bind(this));
32
- this._bindings.on('characteristicsDiscover', this.onCharacteristicsDiscover.bind(this));
33
- this._bindings.on('characteristicsDiscovered', this.onCharacteristicsDiscovered.bind(this));
34
- this._bindings.on('read', this.onRead.bind(this));
35
- this._bindings.on('write', this.onWrite.bind(this));
36
- this._bindings.on('broadcast', this.onBroadcast.bind(this));
37
- this._bindings.on('notify', this.onNotify.bind(this));
38
- this._bindings.on('descriptorsDiscover', this.onDescriptorsDiscover.bind(this));
39
- this._bindings.on('valueRead', this.onValueRead.bind(this));
40
- this._bindings.on('valueWrite', this.onValueWrite.bind(this));
41
- this._bindings.on('handleRead', this.onHandleRead.bind(this));
42
- this._bindings.on('handleWrite', this.onHandleWrite.bind(this));
43
- this._bindings.on('handleNotify', this.onHandleNotify.bind(this));
44
- this._bindings.on('onMtu', this.onMtu.bind(this));
45
-
46
- this.on('warning', (message) => {
47
- if (this.listeners('warning').length === 1) {
48
- console.warn(`noble: ${message}`);
49
- }
50
- });
51
-
52
- // lazy init bindings on first new listener, should be on stateChange
53
- this.on('newListener', (event) => {
54
- if (event === 'stateChange' && !this.initialized) {
55
- this.initialized = true;
56
- process.nextTick(() => {
57
- try {
58
- this._bindings.init();
59
- } catch (error) {
60
- this.emit('warning', 'Initialization of USB device failed: ' + error.message);
61
- }
62
- });
63
- }
64
- });
65
-
66
- // or lazy init bindings if someone attempts to get state first
67
- Object.defineProperties(this, {
68
- state: {
69
- get: function () {
70
- if (!this.initialized) {
71
- this.initialized = true;
72
- this._bindings.init();
73
- }
74
- return this._state;
75
- }
76
- }
77
- });
78
- }
79
-
80
- util.inherits(Noble, events.EventEmitter);
12
+ constructor (bindings) {
13
+ super();
81
14
 
82
- Noble.prototype._cleanupPeriperals = function () {
83
- this._peripherals = {};
84
- this._services = {};
85
- this._characteristics = {};
86
- this._descriptors = {};
87
- this._discoveredPeripheralUUids = {};
88
- };
15
+ this._address = 'unknown';
16
+ this._state = 'unknown';
17
+
18
+ this._initialized = false;
19
+ this._bindings = bindings;
89
20
 
90
- Noble.prototype.onStateChange = function (state) {
91
- debug(`stateChange ${state}`);
21
+ this._discoveredPeripherals = new Set();
22
+ this._peripherals = new Map();
23
+ this._services = {};
24
+ this._characteristics = {};
25
+ this._descriptors = {};
92
26
 
93
- // If the state is poweredOff and the previous state was poweredOn, clean up the peripherals
94
- if (state === 'poweredOff' && this._state === 'poweredOn') {
95
27
  this._cleanupPeriperals();
96
- }
97
-
98
- this._state = state;
99
- this.emit('stateChange', state);
100
- };
101
-
102
- Noble.prototype.onAddressChange = function (address) {
103
- debug(`addressChange ${address}`);
104
28
 
105
- this.address = address;
106
- };
29
+ this.on('warning', message => console.warn(`noble: ${message}`));
107
30
 
108
- Noble.prototype.setScanParameters = function (interval, window, callback) {
109
- if (callback) {
110
- this.once('scanParametersSet', callback);
31
+ this.on('newListener', event => {
32
+ if (event === 'stateChange' && this._initialized === false) {
33
+ this._initialized = true;
34
+ process.nextTick(this._initializeBindings.bind(this));
35
+ }
36
+ });
111
37
  }
112
- this._bindings.setScanParameters(interval, window);
113
- };
114
38
 
115
- Noble.prototype.onScanParametersSet = function () {
116
- debug('scanParametersSet');
117
- this.emit('scanParametersSet');
118
- };
39
+ get state () {
40
+ if (this._initialized === false) {
41
+ this._initializeBindings();
42
+ }
43
+ return this._state;
44
+ }
45
+
46
+ get address () {
47
+ return this._address;
48
+ }
49
+
50
+ _initializeBindings () {
51
+ this._initialized = true;
52
+ this._registerListeners();
53
+ this._bindings.start();
54
+ }
55
+
56
+ _registerListeners () {
57
+ this._bindings.on('stateChange', this._onStateChange.bind(this));
58
+ this._bindings.on('addressChange', this._onAddressChange.bind(this));
59
+ this._bindings.on('scanParametersSet', this._onScanParametersSet.bind(this));
60
+ this._bindings.on('scanStart', this._onScanStart.bind(this));
61
+ this._bindings.on('scanStop', this._onScanStop.bind(this));
62
+ this._bindings.on('discover', this._onDiscover.bind(this));
63
+ this._bindings.on('connect', this._onConnect.bind(this));
64
+ this._bindings.on('disconnect', this._onDisconnect.bind(this));
65
+ this._bindings.on('rssiUpdate', this._onRssiUpdate.bind(this));
66
+ this._bindings.on('servicesDiscover', this._onServicesDiscover.bind(this));
67
+ this._bindings.on('servicesDiscovered', this._onServicesDiscovered.bind(this));
68
+ this._bindings.on('includedServicesDiscover', this._onIncludedServicesDiscover.bind(this));
69
+ this._bindings.on('characteristicsDiscover', this._onCharacteristicsDiscover.bind(this));
70
+ this._bindings.on('characteristicsDiscovered', this._onCharacteristicsDiscovered.bind(this));
71
+ this._bindings.on('read', this._onRead.bind(this));
72
+ this._bindings.on('write', this._onWrite.bind(this));
73
+ this._bindings.on('broadcast', this._onBroadcast.bind(this));
74
+ this._bindings.on('notify', this._onNotify.bind(this));
75
+ this._bindings.on('descriptorsDiscover', this._onDescriptorsDiscover.bind(this));
76
+ this._bindings.on('valueRead', this._onValueRead.bind(this));
77
+ this._bindings.on('valueWrite', this._onValueWrite.bind(this));
78
+ this._bindings.on('handleRead', this._onHandleRead.bind(this));
79
+ this._bindings.on('handleWrite', this._onHandleWrite.bind(this));
80
+ this._bindings.on('handleNotify', this._onHandleNotify.bind(this));
81
+ this._bindings.on('onMtu', this._onMtu.bind(this));
82
+ }
83
+
84
+ _createPeripheral (uuid, address, addressType, connectable, advertisement, rssi, scannable) {
85
+ const peripheral = new Peripheral(this, uuid, address, addressType, connectable, advertisement, rssi, scannable);
86
+
87
+ this._peripherals.set(uuid, peripheral);
88
+ this._services[uuid] = {};
89
+ this._characteristics[uuid] = {};
90
+ this._descriptors[uuid] = {};
119
91
 
120
- Noble.prototype.setAddress = function (address) {
121
- if (this._bindings.setAddress) {
122
- this._bindings.setAddress(address);
123
- } else {
124
- this.emit('warning', 'current binding does not implement setAddress method.');
92
+ return peripheral;
125
93
  }
126
- };
127
94
 
128
- Noble.prototype.waitForPoweredOn = function (timeout = 10000) {
129
- return new Promise((resolve, reject) => {
130
- const timeoutId = setTimeout(() => {
131
- reject(new Error('Timeout waiting for Noble to be powered on'));
132
- }, timeout);
133
-
134
- let listener;
135
- listener = (state) => {
136
- clearTimeout(timeoutId);
137
- if (state === 'poweredOn') {
138
- resolve();
139
- } else {
140
- this.once('stateChange', listener);
95
+ _cleanupPeriperals (uuid = null) {
96
+ const terminateConnection = (peripheral) => {
97
+ if (peripheral.state === 'connecting') {
98
+ // To unblock the async connect call
99
+ this._onConnect(peripheral.id, new Error('cleanup'));
100
+ }
101
+ else if (peripheral.state !== 'disconnected') {
102
+ this._onDisconnect(peripheral.id, 'cleanup');
141
103
  }
142
104
  };
105
+ if (uuid) {
106
+ const peripheral = this._peripherals.get(uuid);
107
+ if (peripheral) {
108
+ terminateConnection(peripheral);
109
+ }
110
+ this._peripherals.delete(uuid);
111
+ this._discoveredPeripherals.delete(uuid);
112
+ delete this._services[uuid];
113
+ delete this._characteristics[uuid];
114
+ delete this._descriptors[uuid];
115
+ } else {
116
+ this._peripherals.forEach(peripheral => terminateConnection(peripheral));
117
+ this._peripherals.clear();
118
+ this._discoveredPeripherals.clear();
119
+ this._services = {};
120
+ this._characteristics = {};
121
+ this._descriptors = {};
122
+ }
123
+ }
143
124
 
144
- this.once('stateChange', listener);
145
- });
146
- };
125
+ _onStateChange (state) {
126
+ debug(`stateChange ${state}`);
147
127
 
148
- const startScanning = function (serviceUuids, allowDuplicates, callback) {
149
- if (typeof serviceUuids === 'function') {
150
- this.emit('warning', 'calling startScanning(callback) is deprecated');
128
+ // If the state is poweredOff and the previous state was poweredOn, clean up the peripherals
129
+ if (state === 'poweredOff' && this._state === 'poweredOn') {
130
+ this._cleanupPeriperals();
131
+ }
132
+
133
+ this._state = state;
134
+ this.emit('stateChange', state);
151
135
  }
152
136
 
153
- if (typeof allowDuplicates === 'function') {
154
- this.emit('warning', 'calling startScanning(serviceUuids, callback) is deprecated');
137
+ _onAddressChange (address) {
138
+ debug(`addressChange ${address}`);
139
+ this._address = address;
140
+ this.emit('addressChange', address);
155
141
  }
156
142
 
157
- const scan = function (state) {
158
- if (state !== 'poweredOn') {
159
- const error = new Error(`Could not start scanning, state is ${state} (not poweredOn)`);
143
+ setScanParameters (interval, window, callback) {
144
+ if (callback) {
145
+ this.once('scanParametersSet', callback);
146
+ }
147
+ this._bindings.setScanParameters(interval, window);
148
+ }
160
149
 
161
- if (typeof callback === 'function') {
162
- callback(error);
163
- } else {
164
- throw error;
165
- }
150
+ _onScanParametersSet () {
151
+ debug('scanParametersSet');
152
+ this.emit('scanParametersSet');
153
+ }
154
+
155
+ setAddress (address) {
156
+ if (this._bindings.setAddress) {
157
+ this._bindings.setAddress(address);
166
158
  } else {
167
- if (callback) {
168
- this.once('scanStart', filterDuplicates => {
169
- callback(null, filterDuplicates);
170
- });
159
+ this.emit('warning', 'current binding does not implement setAddress method.');
160
+ }
161
+ }
162
+
163
+ async waitForPoweredOnAsync (timeout = 10000) {
164
+ return new Promise((resolve, reject) => {
165
+ if (this.state === 'poweredOn') {
166
+ resolve();
167
+ return;
171
168
  }
169
+ const timeoutId = setTimeout(() => {
170
+ reject(new Error('Timeout waiting for Noble to be powered on'));
171
+ }, timeout);
172
+
173
+ const listener = (state) => {
174
+ clearTimeout(timeoutId);
175
+ if (state === 'poweredOn') {
176
+ resolve();
177
+ } else {
178
+ this.once('stateChange', listener);
179
+ }
180
+ };
172
181
 
173
- this._discoveredPeripheralUUids = {};
174
- this._allowDuplicates = allowDuplicates;
182
+ this.once('stateChange', listener);
183
+ });
184
+ }
175
185
 
176
- this._bindings.startScanning(serviceUuids, allowDuplicates);
177
- }
178
- };
186
+ startScanning (serviceUuids, allowDuplicates, callback) {
187
+ const self = this;
188
+ const scan = (state) => {
189
+ if (state !== 'poweredOn') {
190
+ self.once('stateChange', scan.bind(self));
191
+ const error = new Error(`Could not start scanning, state is ${state} (not poweredOn)`);
179
192
 
180
- // if bindings still not init, do it now
181
- if (!this.initialized) {
182
- this.initialized = true;
193
+ if (typeof callback === 'function') {
194
+ callback(error);
195
+ } else {
196
+ throw error;
197
+ }
198
+ } else {
199
+ if (callback) {
200
+ this.once('scanStart', filterDuplicates => callback(null, filterDuplicates));
201
+ }
183
202
 
184
- this._bindings.init();
203
+ this._discoveredPeripherals.clear();
204
+ this._allowDuplicates = allowDuplicates;
185
205
 
186
- this.once('stateChange', scan.bind(this));
187
- } else {
188
- scan.call(this, this._state);
206
+ this._bindings.startScanning(serviceUuids, allowDuplicates);
207
+ }
208
+ };
209
+ // if bindings still not init, do it now
210
+ if (this._initialized === false) {
211
+ this.once('stateChange', scan.bind(this));
212
+ this._initializeBindings();
213
+ } else {
214
+ scan.call(this, this._state);
215
+ }
189
216
  }
190
- };
191
-
192
- Noble.prototype.startScanning = startScanning;
193
- Noble.prototype.startScanningAsync = function (serviceUUIDs, allowDuplicates) {
194
- return util.promisify((callback) => this.startScanning(serviceUUIDs, allowDuplicates, callback))();
195
- };
196
217
 
197
- Noble.prototype.onScanStart = function (filterDuplicates) {
198
- debug('scanStart');
199
- this.emit('scanStart', filterDuplicates);
200
- };
218
+ async startScanningAsync (serviceUUIDs, allowDuplicates) {
219
+ return new Promise((resolve, reject) => {
220
+ this.startScanning(serviceUUIDs, allowDuplicates, error => error ? reject(error) : resolve());
221
+ });
222
+ }
201
223
 
202
- const stopScanning = function (callback) {
203
- if (callback) {
204
- this.once('scanStop', callback);
224
+ _onScanStart (filterDuplicates) {
225
+ debug('scanStart');
226
+ this.emit('scanStart', filterDuplicates);
205
227
  }
206
- if (this._bindings && this.initialized) {
228
+
229
+ stopScanning (callback) {
230
+ if (this._initialized === false || this._bindings === null) {
231
+ callback(new Error('Bindings are not initialized'));
232
+ return;
233
+ }
234
+ if (callback) {
235
+ this.once('scanStop', callback);
236
+ }
207
237
  this._bindings.stopScanning();
208
238
  }
209
- };
210
239
 
211
- Noble.prototype.stopScanning = stopScanning;
212
- Noble.prototype.stopScanningAsync = util.promisify(stopScanning);
240
+ async stopScanningAsync () {
241
+ return new Promise((resolve, reject) => {
242
+ this.stopScanning(error => error ? reject(error) : resolve());
243
+ });
244
+ }
245
+
246
+ async *discoverAsync () {
247
+ const deviceQueue = [];
248
+ let scanning = true;
249
+
250
+ this.once('scanStop', () => scanning = false);
251
+
252
+ const listener = peripheral => deviceQueue.push(peripheral);
253
+ this.on('discover', listener);
254
+
255
+ await this.startScanningAsync();
256
+
257
+ while (scanning || deviceQueue.length > 0) {
258
+ if (deviceQueue.length > 0) {
259
+ yield deviceQueue.shift();
260
+ } else {
261
+ await new Promise(resolve => {
262
+ const tempListener = () => resolve();
263
+ this.once('discover', tempListener);
264
+ setTimeout(tempListener, 1000);
265
+ });
266
+ }
267
+ }
213
268
 
214
- Noble.prototype.onScanStop = function () {
215
- debug('scanStop');
216
- this.emit('scanStop');
217
- };
269
+ await this.stopScanningAsync();
270
+ }
218
271
 
219
- Noble.prototype.reset = function () {
220
- if (this._bindings.reset) {
272
+ _onScanStop () {
273
+ debug('scanStop');
274
+ this.emit('scanStop');
275
+ }
276
+
277
+ reset () {
278
+ if (typeof this._bindings.reset !== 'function') { return; }
221
279
  this._bindings.reset();
222
- }
223
- };
280
+ }
224
281
 
225
- Noble.prototype.stop = function () {
226
- if (this._bindings.stop) {
282
+ stop () {
283
+ if (typeof this._bindings.stop !== 'function') { return; }
227
284
  this._bindings.stop();
228
285
  }
229
- };
230
286
 
231
- Noble.prototype.onDiscover = function (uuid, address, addressType, connectable, advertisement, rssi, scannable) {
232
- let peripheral = this._peripherals[uuid];
287
+ _onDiscover (uuid, address, addressType, connectable, advertisement, rssi, scannable) {
288
+ let peripheral = this._peripherals.get(uuid);
233
289
 
234
- if (!peripheral) {
235
- peripheral = new Peripheral(this, uuid, address, addressType, connectable, advertisement, rssi, scannable);
236
-
237
- this._peripherals[uuid] = peripheral;
238
- this._services[uuid] = {};
239
- this._characteristics[uuid] = {};
240
- this._descriptors[uuid] = {};
241
- } else {
242
- // "or" the advertisment data with existing
243
- for (const i in advertisement) {
244
- if (advertisement[i] !== undefined) {
245
- peripheral.advertisement[i] = advertisement[i];
290
+ if (!peripheral) {
291
+ peripheral = this._createPeripheral(uuid, address, addressType, connectable, advertisement, rssi, scannable);
292
+ } else {
293
+ // "or" the advertisment data with existing
294
+ for (const i in advertisement) {
295
+ if (advertisement[i] !== undefined) {
296
+ peripheral.advertisement[i] = advertisement[i];
297
+ }
246
298
  }
247
- }
248
299
 
249
- peripheral.connectable = connectable;
250
- peripheral.scannable = scannable;
251
- peripheral.rssi = rssi;
252
- }
300
+ peripheral.connectable = connectable;
301
+ peripheral.scannable = scannable;
302
+ peripheral.rssi = rssi;
303
+ }
253
304
 
254
- const previouslyDiscoverd = this._discoveredPeripheralUUids[uuid] === true;
305
+ const previouslyDiscoverd = this._discoveredPeripherals.has(uuid);
255
306
 
256
- if (!previouslyDiscoverd) {
257
- this._discoveredPeripheralUUids[uuid] = true;
307
+ if (!previouslyDiscoverd) {
308
+ this._discoveredPeripherals.add(uuid);
309
+ }
310
+ if (this._allowDuplicates || !previouslyDiscoverd || (!scannable && !connectable)) {
311
+ this.emit('discover', peripheral);
312
+ }
258
313
  }
259
314
 
260
- if (this._allowDuplicates || !previouslyDiscoverd || (!scannable && !connectable)) {
261
- this.emit('discover', peripheral);
315
+ _getPeripheralId (idOrAddress) {
316
+ let identifier;
317
+ // Convert the peripheralId to an identifier
318
+ if (/^[0-9A-Fa-f]+$/.test(idOrAddress) === false) {
319
+ identifier = this._bindings.addressToId(idOrAddress);
320
+ if (identifier === null) {
321
+ throw new Error(`Invalid peripheral ID or Address ${idOrAddress}`);
322
+ }
323
+ } else {
324
+ identifier = idOrAddress;
325
+ }
326
+ return identifier;
262
327
  }
263
- };
264
328
 
265
- Noble.prototype.connect = function (peripheralUuid, parameters, callback) {
266
- // Check if callback is a function
267
- if (typeof callback === 'function') {
268
- // Create a unique event name using the peripheral UUID
269
- const eventName = `connect:${peripheralUuid}`;
329
+ connect (idOrAddress, parameters, callback) {
330
+ // Get the identifier for the peripheral
331
+ const identifier = this._getPeripheralId(idOrAddress);
332
+ // Check if callback is a function
333
+ if (typeof callback === 'function') {
334
+ // Add a one-time listener for this specific event
335
+ this.once(`connect:${identifier}`, error => callback(error, this._peripherals.get(identifier)));
336
+ }
270
337
 
271
- // Add a one-time listener for this specific event
272
- this.once(eventName, (error) => {
273
- callback(error, this._peripherals[peripheralUuid]);
338
+ // Proceed to initiate the connection
339
+ this._bindings.connect(identifier, parameters);
340
+ }
341
+
342
+ async connectAsync (idOrAddress, parameters) {
343
+ return new Promise((resolve, reject) => {
344
+ this.connect(idOrAddress, parameters, (error, peripheral) => error ? reject(error) : resolve(peripheral));
274
345
  });
275
346
  }
276
347
 
277
- // Proceed to initiate the connection
278
- this._bindings.connect(peripheralUuid, parameters);
279
- };
280
- Noble.prototype.connectAsync = function (peripheralUuid, parameters) {
281
- return util.promisify((callback) => this.connect(peripheralUuid, parameters, callback))();
282
- };
283
-
284
- Noble.prototype.onConnect = function (peripheralUuid, error) {
285
- const peripheral = this._peripherals[peripheralUuid];
348
+ _onConnect (peripheralId, error) {
349
+ const peripheral = this._peripherals.get(peripheralId);
286
350
 
287
- if (peripheral) {
288
- // Emit a unique connect event for the specific peripheral
289
- this.emit(`connect:${peripheralUuid}`, error);
351
+ if (peripheral) {
352
+ // Emit a unique connect event for the specific peripheral
353
+ this.emit(`connect:${peripheralId}`, error);
290
354
 
291
- peripheral.state = error ? 'error' : 'connected';
292
- // Also emit the general 'connect' event for a peripheral
293
- peripheral.emit('connect', error);
294
- } else {
295
- this.emit('warning', `unknown peripheral ${peripheralUuid} connected!`);
355
+ peripheral.state = error ? 'error' : 'connected';
356
+ // Also emit the general 'connect' event for a peripheral
357
+ peripheral.emit('connect', error);
358
+ } else {
359
+ this.emit('warning', `unknown peripheral ${peripheralId} connected!`);
360
+ }
296
361
  }
297
- };
298
-
299
- Noble.prototype.cancelConnect = function (peripheralUuid, parameters) {
300
- this._bindings.cancelConnect(peripheralUuid, parameters);
301
- };
302
-
303
- Noble.prototype.disconnect = function (peripheralUuid) {
304
- this._bindings.disconnect(peripheralUuid);
305
- };
306
-
307
- Noble.prototype.onDisconnect = function (peripheralUuid, reason) {
308
- const peripheral = this._peripherals[peripheralUuid];
309
362
 
310
- if (peripheral) {
311
- peripheral.state = 'disconnected';
312
- peripheral.emit('disconnect', reason);
313
- } else {
314
- this.emit('warning', `unknown peripheral ${peripheralUuid} disconnected!`);
363
+ cancelConnect (idOrAddress, parameters) {
364
+ // Get the identifier for the peripheral
365
+ const identifier = this._getPeripheralId(idOrAddress);
366
+
367
+ // Check if the peripheral is connecting
368
+ const peripheral = this._peripherals.get(identifier);
369
+ if (peripheral && peripheral.state === 'connecting') {
370
+ peripheral.state = 'disconnected';
371
+ }
372
+ // Emit a unique connect event for the specific peripheral
373
+ this.emit(`connect:${identifier}`, new Error('connection canceled!'));
374
+ // Cancel the connection
375
+ this._bindings.cancelConnect(identifier, parameters);
315
376
  }
316
- };
317
-
318
- Noble.prototype.updateRssi = function (peripheralUuid) {
319
- this._bindings.updateRssi(peripheralUuid);
320
- };
321
377
 
322
- Noble.prototype.onRssiUpdate = function (peripheralUuid, rssi) {
323
- const peripheral = this._peripherals[peripheralUuid];
324
-
325
- if (peripheral) {
326
- peripheral.rssi = rssi;
327
-
328
- peripheral.emit('rssiUpdate', rssi);
329
- } else {
330
- this.emit('warning', `unknown peripheral ${peripheralUuid} RSSI update!`);
378
+ disconnect (peripheralId) {
379
+ // Disconnect the peripheral
380
+ this._bindings.disconnect(peripheralId);
331
381
  }
332
- };
333
382
 
334
- /// add an array of service objects (as retrieved via the servicesDiscovered event)
335
- Noble.prototype.addServices = function (peripheralUuid, services) {
336
- const servObjs = [];
383
+ _onDisconnect (peripheralId, reason) {
384
+ const peripheral = this._peripherals.get(peripheralId);
337
385
 
338
- for (let i = 0; i < services.length; i++) {
339
- const o = this.addService(peripheralUuid, services[i]);
340
- servObjs.push(o);
386
+ if (peripheral) {
387
+ peripheral.state = 'disconnected';
388
+ peripheral.emit('disconnect', reason);
389
+ this.emit(`disconnect:${peripheralId}`, reason);
390
+ } else {
391
+ this.emit('warning', `unknown peripheral ${peripheralId} disconnected!`);
392
+ }
341
393
  }
342
- return servObjs;
343
- };
344
-
345
- /// service is a ServiceObject { uuid, startHandle, endHandle,..}
346
- Noble.prototype.addService = function (peripheralUuid, service) {
347
- const peripheral = this._peripherals[peripheralUuid];
348
394
 
349
- // pass on to lower layers (gatt)
350
- if (this._bindings.addService) {
351
- this._bindings.addService(peripheralUuid, service);
395
+ updateRssi (peripheralId) {
396
+ this._bindings.updateRssi(peripheralId);
352
397
  }
353
398
 
354
- if (!peripheral.services) {
355
- peripheral.services = [];
356
- }
357
- // allocate internal service object and return
358
- const serv = new Service(this, peripheralUuid, service.uuid);
399
+ _onRssiUpdate (peripheralId, rssi, error) {
400
+ const peripheral = this._peripherals.get(peripheralId);
359
401
 
360
- this._services[peripheralUuid][service.uuid] = serv;
361
- this._characteristics[peripheralUuid][service.uuid] = {};
362
- this._descriptors[peripheralUuid][service.uuid] = {};
402
+ if (peripheral) {
403
+ peripheral.rssi = rssi;
363
404
 
364
- peripheral.services.push(serv);
405
+ peripheral.emit('rssiUpdate', rssi, error);
406
+ } else {
407
+ this.emit('warning', `unknown peripheral ${peripheralId} RSSI update!`);
408
+ }
409
+ }
365
410
 
366
- return serv;
367
- };
411
+ /// add an array of service objects (as retrieved via the servicesDiscovered event)
412
+ addServices (peripheralId, services) {
413
+ const servObjs = [];
368
414
 
369
- /// callback receiving a list of service objects from the gatt layer
370
- Noble.prototype.onServicesDiscovered = function (peripheralUuid, services) {
371
- const peripheral = this._peripherals[peripheralUuid];
415
+ for (let i = 0; i < services.length; i++) {
416
+ const o = this.addService(peripheralId, services[i]);
417
+ servObjs.push(o);
418
+ }
419
+ return servObjs;
420
+ }
372
421
 
373
- if (peripheral) { peripheral.emit('servicesDiscovered', peripheral, services); } // pass on to higher layers
374
- };
422
+ /// service is a ServiceObject { uuid, startHandle, endHandle,..}
423
+ addService (peripheralId, service) {
424
+ const peripheral = this._peripherals.get(peripheralId);
375
425
 
376
- Noble.prototype.discoverServices = function (peripheralUuid, uuids) {
377
- this._bindings.discoverServices(peripheralUuid, uuids);
378
- };
426
+ // pass on to lower layers (gatt)
427
+ if (this._bindings.addService) {
428
+ this._bindings.addService(peripheralId, service);
429
+ }
379
430
 
380
- Noble.prototype.onServicesDiscover = function (peripheralUuid, serviceUuids) {
381
- const peripheral = this._peripherals[peripheralUuid];
431
+ if (!peripheral.services) {
432
+ peripheral.services = [];
433
+ }
434
+ // allocate internal service object and return
435
+ const serv = new Service(this, peripheralId, service.uuid);
382
436
 
383
- if (peripheral) {
384
- const services = [];
437
+ this._services[peripheralId][service.uuid] = serv;
438
+ this._characteristics[peripheralId][service.uuid] = {};
439
+ this._descriptors[peripheralId][service.uuid] = {};
385
440
 
386
- for (let i = 0; i < serviceUuids.length; i++) {
387
- const serviceUuid = serviceUuids[i];
388
- const service = new Service(this, peripheralUuid, serviceUuid);
441
+ peripheral.services.push(serv);
389
442
 
390
- this._services[peripheralUuid][serviceUuid] = service;
391
- this._characteristics[peripheralUuid][serviceUuid] = {};
392
- this._descriptors[peripheralUuid][serviceUuid] = {};
443
+ return serv;
444
+ }
393
445
 
394
- services.push(service);
395
- }
446
+ /// callback receiving a list of service objects from the gatt layer
447
+ _onServicesDiscovered (peripheralId, services) {
448
+ const peripheral = this._peripherals.get(peripheralId);
396
449
 
397
- peripheral.services = services;
450
+ if (peripheral) { peripheral.emit('servicesDiscovered', peripheral, services); } // pass on to higher layers
451
+ }
398
452
 
399
- peripheral.emit('servicesDiscover', services);
400
- } else {
401
- this.emit('warning', `unknown peripheral ${peripheralUuid} services discover!`);
453
+ discoverServices (peripheralId, uuids) {
454
+ this._bindings.discoverServices(peripheralId, uuids);
402
455
  }
403
- };
404
456
 
405
- Noble.prototype.discoverIncludedServices = function (peripheralUuid, serviceUuid, serviceUuids) {
406
- this._bindings.discoverIncludedServices(peripheralUuid, serviceUuid, serviceUuids);
407
- };
457
+ _onServicesDiscover (peripheralId, serviceUuids, error) {
458
+ const peripheral = this._peripherals.get(peripheralId);
408
459
 
409
- Noble.prototype.onIncludedServicesDiscover = function (peripheralUuid, serviceUuid, includedServiceUuids) {
410
- const service = this._services[peripheralUuid][serviceUuid];
460
+ if (peripheral) {
461
+ const services = [];
411
462
 
412
- if (service) {
413
- service.includedServiceUuids = includedServiceUuids;
463
+ for (let i = 0; i < serviceUuids.length; i++) {
464
+ const serviceUuid = serviceUuids[i];
465
+ const service = new Service(this, peripheralId, serviceUuid);
414
466
 
415
- service.emit('includedServicesDiscover', includedServiceUuids);
416
- } else {
417
- this.emit('warning', `unknown peripheral ${peripheralUuid}, ${serviceUuid} included services discover!`);
418
- }
419
- };
467
+ this._services[peripheralId][serviceUuid] = service;
468
+ this._characteristics[peripheralId][serviceUuid] = {};
469
+ this._descriptors[peripheralId][serviceUuid] = {};
420
470
 
421
- /// add characteristics to the peripheral; returns an array of initialized Characteristics objects
422
- Noble.prototype.addCharacteristics = function (peripheralUuid, serviceUuid, characteristics) {
423
- // first, initialize gatt layer:
424
- if (this._bindings.addCharacteristics) {
425
- this._bindings.addCharacteristics(peripheralUuid, serviceUuid, characteristics);
426
- }
471
+ services.push(service);
472
+ }
427
473
 
428
- const service = this._services[peripheralUuid][serviceUuid];
429
- if (!service) {
430
- this.emit('warning', `unknown service ${peripheralUuid}, ${serviceUuid} characteristics discover!`);
431
- return;
474
+ peripheral.services = services;
475
+
476
+ peripheral.emit('servicesDiscover', services, error);
477
+ } else {
478
+ this.emit('warning', `unknown peripheral ${peripheralId} services discover!`);
479
+ }
432
480
  }
433
481
 
434
- const characteristics_ = [];
435
- for (let i = 0; i < characteristics.length; i++) {
436
- const characteristicUuid = characteristics[i].uuid;
482
+ discoverIncludedServices (peripheralId, serviceUuid, serviceUuids) {
483
+ this._bindings.discoverIncludedServices(peripheralId, serviceUuid, serviceUuids);
484
+ }
437
485
 
438
- const characteristic = new Characteristic(
439
- this,
440
- peripheralUuid,
441
- serviceUuid,
442
- characteristicUuid,
443
- characteristics[i].properties
444
- );
486
+ _onIncludedServicesDiscover (peripheralId, serviceUuid, includedServiceUuids, error) {
487
+ const service = this._services[peripheralId][serviceUuid];
445
488
 
446
- this._characteristics[peripheralUuid][serviceUuid][characteristicUuid] = characteristic;
447
- this._descriptors[peripheralUuid][serviceUuid][characteristicUuid] = {};
489
+ if (service) {
490
+ service.includedServiceUuids = includedServiceUuids;
448
491
 
449
- characteristics_.push(characteristic);
492
+ service.emit('includedServicesDiscover', includedServiceUuids, error);
493
+ } else {
494
+ this.emit('warning', `unknown peripheral ${peripheralId}, ${serviceUuid} included services discover!`);
495
+ }
450
496
  }
451
- service.characteristics = characteristics_;
452
- return characteristics_;
453
- };
454
-
455
- Noble.prototype.onCharacteristicsDiscovered = function (peripheralUuid, serviceUuid, characteristics) {
456
- const service = this._services[peripheralUuid][serviceUuid];
457
-
458
- service.emit('characteristicsDiscovered', characteristics);
459
- };
460
497
 
461
- Noble.prototype.discoverCharacteristics = function (peripheralUuid, serviceUuid, characteristicUuids) {
462
- this._bindings.discoverCharacteristics(peripheralUuid, serviceUuid, characteristicUuids);
463
- };
498
+ /// add characteristics to the peripheral; returns an array of initialized Characteristics objects
499
+ addCharacteristics (peripheralId, serviceUuid, characteristics) {
500
+ // first, initialize gatt layer:
501
+ if (this._bindings.addCharacteristics) {
502
+ this._bindings.addCharacteristics(peripheralId, serviceUuid, characteristics);
503
+ }
464
504
 
465
- Noble.prototype.onCharacteristicsDiscover = function (peripheralUuid, serviceUuid, characteristics) {
466
- const service = this._services[peripheralUuid][serviceUuid];
505
+ const service = this._services[peripheralId][serviceUuid];
506
+ if (!service) {
507
+ this.emit('warning', `unknown service ${peripheralId}, ${serviceUuid} characteristics discover!`);
508
+ return;
509
+ }
467
510
 
468
- if (service) {
469
511
  const characteristics_ = [];
470
-
471
512
  for (let i = 0; i < characteristics.length; i++) {
472
513
  const characteristicUuid = characteristics[i].uuid;
473
514
 
474
515
  const characteristic = new Characteristic(
475
516
  this,
476
- peripheralUuid,
517
+ peripheralId,
477
518
  serviceUuid,
478
519
  characteristicUuid,
479
520
  characteristics[i].properties
480
521
  );
481
522
 
482
- this._characteristics[peripheralUuid][serviceUuid][characteristicUuid] = characteristic;
483
- this._descriptors[peripheralUuid][serviceUuid][characteristicUuid] = {};
523
+ this._characteristics[peripheralId][serviceUuid][characteristicUuid] = characteristic;
524
+ this._descriptors[peripheralId][serviceUuid][characteristicUuid] = {};
484
525
 
485
526
  characteristics_.push(characteristic);
486
527
  }
487
-
488
528
  service.characteristics = characteristics_;
529
+ return characteristics_;
530
+ }
489
531
 
490
- service.emit('characteristicsDiscover', characteristics_);
491
- } else {
492
- this.emit('warning', `unknown peripheral ${peripheralUuid}, ${serviceUuid} characteristics discover!`);
532
+ _onCharacteristicsDiscovered (peripheralId, serviceUuid, characteristics) {
533
+ const service = this._services[peripheralId][serviceUuid];
534
+
535
+ service.emit('characteristicsDiscovered', characteristics);
536
+ }
537
+
538
+ discoverCharacteristics (peripheralId, serviceUuid, characteristicUuids) {
539
+ this._bindings.discoverCharacteristics(peripheralId, serviceUuid, characteristicUuids);
493
540
  }
494
- };
495
541
 
496
- Noble.prototype.read = function (peripheralUuid, serviceUuid, characteristicUuid) {
497
- this._bindings.read(peripheralUuid, serviceUuid, characteristicUuid);
498
- };
542
+ _onCharacteristicsDiscover (peripheralId, serviceUuid, characteristics, error) {
543
+ const service = this._services[peripheralId][serviceUuid];
499
544
 
500
- Noble.prototype.onRead = function (peripheralUuid, serviceUuid, characteristicUuid, data, isNotification) {
501
- const characteristic = this._characteristics[peripheralUuid][serviceUuid][characteristicUuid];
545
+ if (service) {
546
+ const characteristics_ = [];
502
547
 
503
- if (characteristic) {
504
- characteristic.emit('data', data, isNotification);
548
+ for (let i = 0; i < characteristics.length; i++) {
549
+ const characteristicUuid = characteristics[i].uuid;
505
550
 
506
- characteristic.emit('read', data, isNotification); // for backwards compatbility
507
- } else {
508
- this.emit('warning', `unknown peripheral ${peripheralUuid}, ${serviceUuid}, ${characteristicUuid} read!`);
551
+ const characteristic = new Characteristic(
552
+ this,
553
+ peripheralId,
554
+ serviceUuid,
555
+ characteristicUuid,
556
+ characteristics[i].properties
557
+ );
558
+
559
+ this._characteristics[peripheralId][serviceUuid][characteristicUuid] = characteristic;
560
+ this._descriptors[peripheralId][serviceUuid][characteristicUuid] = {};
561
+
562
+ characteristics_.push(characteristic);
563
+ }
564
+
565
+ service.characteristics = characteristics_;
566
+
567
+ service.emit('characteristicsDiscover', characteristics_, error);
568
+ } else {
569
+ this.emit('warning', `unknown peripheral ${peripheralId}, ${serviceUuid} characteristics discover!`);
570
+ }
509
571
  }
510
- };
511
572
 
512
- Noble.prototype.write = function (peripheralUuid, serviceUuid, characteristicUuid, data, withoutResponse) {
513
- this._bindings.write(peripheralUuid, serviceUuid, characteristicUuid, data, withoutResponse);
514
- };
573
+ read (peripheralId, serviceUuid, characteristicUuid) {
574
+ this._bindings.read(peripheralId, serviceUuid, characteristicUuid);
575
+ }
515
576
 
516
- Noble.prototype.onWrite = function (peripheralUuid, serviceUuid, characteristicUuid) {
517
- const characteristic = this._characteristics[peripheralUuid][serviceUuid][characteristicUuid];
577
+ _onRead (peripheralId, serviceUuid, characteristicUuid, data, isNotification, error) {
578
+ const characteristic = this._characteristics[peripheralId][serviceUuid][characteristicUuid];
518
579
 
519
- if (characteristic) {
520
- characteristic.emit('write');
521
- } else {
522
- this.emit('warning', `unknown peripheral ${peripheralUuid}, ${serviceUuid}, ${characteristicUuid} write!`);
580
+ if (characteristic) {
581
+ characteristic.emit('read', data, isNotification, error);
582
+ } else {
583
+ this.emit('warning', `unknown peripheral ${peripheralId}, ${serviceUuid}, ${characteristicUuid} read!`);
584
+ }
523
585
  }
524
- };
525
586
 
526
- Noble.prototype.broadcast = function (peripheralUuid, serviceUuid, characteristicUuid, broadcast) {
527
- this._bindings.broadcast(peripheralUuid, serviceUuid, characteristicUuid, broadcast);
528
- };
587
+ write (peripheralId, serviceUuid, characteristicUuid, data, withoutResponse) {
588
+ this._bindings.write(peripheralId, serviceUuid, characteristicUuid, data, withoutResponse);
589
+ }
529
590
 
530
- Noble.prototype.onBroadcast = function (peripheralUuid, serviceUuid, characteristicUuid, state) {
531
- const characteristic = this._characteristics[peripheralUuid][serviceUuid][characteristicUuid];
591
+ _onWrite (peripheralId, serviceUuid, characteristicUuid, error) {
592
+ const characteristic = this._characteristics[peripheralId][serviceUuid][characteristicUuid];
532
593
 
533
- if (characteristic) {
534
- characteristic.emit('broadcast', state);
535
- } else {
536
- this.emit('warning', `unknown peripheral ${peripheralUuid}, ${serviceUuid}, ${characteristicUuid} broadcast!`);
594
+ if (characteristic) {
595
+ characteristic.emit('write', error);
596
+ } else {
597
+ this.emit('warning', `unknown peripheral ${peripheralId}, ${serviceUuid}, ${characteristicUuid} write!`);
598
+ }
537
599
  }
538
- };
539
600
 
540
- Noble.prototype.notify = function (peripheralUuid, serviceUuid, characteristicUuid, notify) {
541
- this._bindings.notify(peripheralUuid, serviceUuid, characteristicUuid, notify);
542
- };
601
+ broadcast (peripheralId, serviceUuid, characteristicUuid, broadcast) {
602
+ this._bindings.broadcast(peripheralId, serviceUuid, characteristicUuid, broadcast);
603
+ }
604
+
605
+ _onBroadcast (peripheralId, serviceUuid, characteristicUuid, state) {
606
+ const characteristic = this._characteristics[peripheralId][serviceUuid][characteristicUuid];
607
+
608
+ if (characteristic) {
609
+ characteristic.emit('broadcast', state);
610
+ } else {
611
+ this.emit('warning', `unknown peripheral ${peripheralId}, ${serviceUuid}, ${characteristicUuid} broadcast!`);
612
+ }
613
+ }
543
614
 
544
- Noble.prototype.onNotify = function (peripheralUuid, serviceUuid, characteristicUuid, state) {
545
- const characteristic = this._characteristics[peripheralUuid][serviceUuid][characteristicUuid];
615
+ notify (peripheralId, serviceUuid, characteristicUuid, notify) {
616
+ this._bindings.notify(peripheralId, serviceUuid, characteristicUuid, notify);
617
+ }
546
618
 
547
- if (characteristic) {
548
- characteristic.emit('notify', state);
549
- } else {
550
- this.emit('warning', `unknown peripheral ${peripheralUuid}, ${serviceUuid}, ${characteristicUuid} notify!`);
619
+ _onNotify (peripheralId, serviceUuid, characteristicUuid, state, error) {
620
+ const characteristic = this._characteristics[peripheralId][serviceUuid][characteristicUuid];
621
+ if (characteristic) {
622
+ characteristic.emit('notify', state, error);
623
+ } else {
624
+ this.emit('warning', `unknown peripheral ${peripheralId}, ${serviceUuid}, ${characteristicUuid} notify!`);
625
+ }
551
626
  }
552
- };
553
627
 
554
- Noble.prototype.discoverDescriptors = function (peripheralUuid, serviceUuid, characteristicUuid) {
555
- this._bindings.discoverDescriptors(peripheralUuid, serviceUuid, characteristicUuid);
556
- };
628
+ discoverDescriptors (peripheralId, serviceUuid, characteristicUuid) {
629
+ this._bindings.discoverDescriptors(peripheralId, serviceUuid, characteristicUuid);
630
+ }
557
631
 
558
- Noble.prototype.onDescriptorsDiscover = function (peripheralUuid, serviceUuid, characteristicUuid, descriptors) {
559
- const characteristic = this._characteristics[peripheralUuid][serviceUuid][characteristicUuid];
632
+ _onDescriptorsDiscover (peripheralId, serviceUuid, characteristicUuid, descriptors, error) {
633
+ const characteristic = this._characteristics[peripheralId][serviceUuid][characteristicUuid];
560
634
 
561
- if (characteristic) {
562
- const descriptors_ = [];
635
+ if (characteristic) {
636
+ const descriptors_ = [];
563
637
 
564
- for (let i = 0; i < descriptors.length; i++) {
565
- const descriptorUuid = descriptors[i];
638
+ for (let i = 0; i < descriptors.length; i++) {
639
+ const descriptorUuid = descriptors[i];
566
640
 
567
- const descriptor = new Descriptor(
568
- this,
569
- peripheralUuid,
570
- serviceUuid,
571
- characteristicUuid,
572
- descriptorUuid
573
- );
641
+ const descriptor = new Descriptor(
642
+ this,
643
+ peripheralId,
644
+ serviceUuid,
645
+ characteristicUuid,
646
+ descriptorUuid
647
+ );
574
648
 
575
- this._descriptors[peripheralUuid][serviceUuid][characteristicUuid][descriptorUuid] = descriptor;
649
+ this._descriptors[peripheralId][serviceUuid][characteristicUuid][descriptorUuid] = descriptor;
576
650
 
577
- descriptors_.push(descriptor);
578
- }
651
+ descriptors_.push(descriptor);
652
+ }
579
653
 
580
- characteristic.descriptors = descriptors_;
654
+ characteristic.descriptors = descriptors_;
581
655
 
582
- characteristic.emit('descriptorsDiscover', descriptors_);
583
- } else {
584
- this.emit('warning', `unknown peripheral ${peripheralUuid}, ${serviceUuid}, ${characteristicUuid} descriptors discover!`);
656
+ characteristic.emit('descriptorsDiscover', descriptors_, error);
657
+ } else {
658
+ this.emit('warning', `unknown peripheral ${peripheralId}, ${serviceUuid}, ${characteristicUuid} descriptors discover!`);
659
+ }
585
660
  }
586
- };
587
661
 
588
- Noble.prototype.readValue = function (peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid) {
589
- this._bindings.readValue(peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid);
590
- };
662
+ readValue (peripheralId, serviceUuid, characteristicUuid, descriptorUuid) {
663
+ this._bindings.readValue(peripheralId, serviceUuid, characteristicUuid, descriptorUuid);
664
+ }
591
665
 
592
- Noble.prototype.onValueRead = function (peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid, data) {
593
- const descriptor = this._descriptors[peripheralUuid][serviceUuid][characteristicUuid][descriptorUuid];
666
+ _onValueRead (peripheralId, serviceUuid, characteristicUuid, descriptorUuid, data, error) {
667
+ const descriptor = this._descriptors[peripheralId][serviceUuid][characteristicUuid][descriptorUuid];
594
668
 
595
- if (descriptor) {
596
- descriptor.emit('valueRead', data);
597
- } else {
598
- this.emit('warning', `unknown peripheral ${peripheralUuid}, ${serviceUuid}, ${characteristicUuid}, ${descriptorUuid} value read!`);
669
+ if (descriptor) {
670
+ descriptor.emit('valueRead', data, error);
671
+ } else {
672
+ this.emit('warning', `unknown peripheral ${peripheralId}, ${serviceUuid}, ${characteristicUuid}, ${descriptorUuid} value read!`);
673
+ }
599
674
  }
600
- };
601
675
 
602
- Noble.prototype.writeValue = function (peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid, data) {
603
- this._bindings.writeValue(peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid, data);
604
- };
676
+ writeValue (peripheralId, serviceUuid, characteristicUuid, descriptorUuid, data) {
677
+ this._bindings.writeValue(peripheralId, serviceUuid, characteristicUuid, descriptorUuid, data);
678
+ }
605
679
 
606
- Noble.prototype.onValueWrite = function (peripheralUuid, serviceUuid, characteristicUuid, descriptorUuid) {
607
- const descriptor = this._descriptors[peripheralUuid][serviceUuid][characteristicUuid][descriptorUuid];
680
+ _onValueWrite (peripheralId, serviceUuid, characteristicUuid, descriptorUuid, error) {
681
+ const descriptor = this._descriptors[peripheralId][serviceUuid][characteristicUuid][descriptorUuid];
608
682
 
609
- if (descriptor) {
610
- descriptor.emit('valueWrite');
611
- } else {
612
- this.emit('warning', `unknown peripheral ${peripheralUuid}, ${serviceUuid}, ${characteristicUuid}, ${descriptorUuid} value write!`);
683
+ if (descriptor) {
684
+ descriptor.emit('valueWrite', error);
685
+ } else {
686
+ this.emit('warning', `unknown peripheral ${peripheralId}, ${serviceUuid}, ${characteristicUuid}, ${descriptorUuid} value write!`);
687
+ }
613
688
  }
614
- };
615
689
 
616
- Noble.prototype.readHandle = function (peripheralUuid, handle) {
617
- this._bindings.readHandle(peripheralUuid, handle);
618
- };
690
+ readHandle (peripheralId, handle) {
691
+ this._bindings.readHandle(peripheralId, handle);
692
+ }
619
693
 
620
- Noble.prototype.onHandleRead = function (peripheralUuid, handle, data) {
621
- const peripheral = this._peripherals[peripheralUuid];
694
+ _onHandleRead (peripheralId, handle, data, error) {
695
+ const peripheral = this._peripherals.get(peripheralId);
622
696
 
623
- if (peripheral) {
624
- peripheral.emit(`handleRead${handle}`, data);
625
- } else {
626
- this.emit('warning', `unknown peripheral ${peripheralUuid} handle read!`);
697
+ if (peripheral) {
698
+ peripheral.emit(`handleRead${handle}`, data, error);
699
+ } else {
700
+ this.emit('warning', `unknown peripheral ${peripheralId} handle read!`);
701
+ }
627
702
  }
628
- };
629
703
 
630
- Noble.prototype.writeHandle = function (peripheralUuid, handle, data, withoutResponse) {
631
- this._bindings.writeHandle(peripheralUuid, handle, data, withoutResponse);
632
- };
704
+ writeHandle (peripheralId, handle, data, withoutResponse) {
705
+ this._bindings.writeHandle(peripheralId, handle, data, withoutResponse);
706
+ }
633
707
 
634
- Noble.prototype.onHandleWrite = function (peripheralUuid, handle) {
635
- const peripheral = this._peripherals[peripheralUuid];
708
+ _onHandleWrite (peripheralId, handle, error) {
709
+ const peripheral = this._peripherals.get(peripheralId);
636
710
 
637
- if (peripheral) {
638
- peripheral.emit(`handleWrite${handle}`);
639
- } else {
640
- this.emit('warning', `unknown peripheral ${peripheralUuid} handle write!`);
711
+ if (peripheral) {
712
+ peripheral.emit(`handleWrite${handle}`, error);
713
+ } else {
714
+ this.emit('warning', `unknown peripheral ${peripheralId} handle write!`);
715
+ }
641
716
  }
642
- };
643
717
 
644
- Noble.prototype.onHandleNotify = function (peripheralUuid, handle, data) {
645
- const peripheral = this._peripherals[peripheralUuid];
718
+ _onHandleNotify (peripheralId, handle, data, error) {
719
+ const peripheral = this._peripherals.get(peripheralId);
646
720
 
647
- if (peripheral) {
648
- peripheral.emit('handleNotify', handle, data);
649
- } else {
650
- this.emit('warning', `unknown peripheral ${peripheralUuid} handle notify!`);
721
+ if (peripheral) {
722
+ peripheral.emit('handleNotify', handle, data, error);
723
+ } else {
724
+ this.emit('warning', `unknown peripheral ${peripheralId} handle notify!`);
725
+ }
651
726
  }
652
- };
653
727
 
654
- Noble.prototype.onMtu = function (peripheralUuid, mtu) {
655
- const peripheral = this._peripherals[peripheralUuid];
656
- if (peripheral && mtu) peripheral.mtu = mtu;
657
- };
728
+ _onMtu (peripheralId, mtu) {
729
+ const peripheral = this._peripherals.get(peripheralId);
730
+ if (peripheral && mtu) {
731
+ peripheral.mtu = mtu;
732
+ peripheral.emit('mtu', mtu);
733
+ }
734
+ }
735
+
736
+ async _withDisconnectHandler (peripheralId, operation) {
737
+ return new Promise((resolve, reject) => {
738
+ const disconnectListener = error => reject(error);
739
+ this.once(`disconnect:${peripheralId}`, disconnectListener);
740
+
741
+ Promise.resolve(operation())
742
+ .then(result => {
743
+ this.removeListener(`disconnect:${peripheralId}`, disconnectListener);
744
+ resolve(result);
745
+ })
746
+ .catch(error => {
747
+ this.removeListener(`disconnect:${peripheralId}`, disconnectListener);
748
+ reject(error);
749
+ });
750
+ });
751
+ }
752
+ }
658
753
 
659
754
  module.exports = Noble;