@ledgerhq/react-native-hw-transport-ble 6.29.5 → 6.30.0-nightly.0

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.
@@ -32,8 +32,8 @@ import {
32
32
  getInfosForServiceUuid,
33
33
  } from "@ledgerhq/devices";
34
34
  import type { DeviceModel } from "@ledgerhq/devices";
35
- import { log } from "@ledgerhq/logs";
36
- import { Observable, defer, merge, from, of, throwError, Observer } from "rxjs";
35
+ import { trace, LocalTracer, TraceContext } from "@ledgerhq/logs";
36
+ import { Observable, defer, merge, from, of, throwError, Observer, firstValueFrom } from "rxjs";
37
37
  import { share, ignoreElements, first, map, tap, catchError } from "rxjs/operators";
38
38
  import {
39
39
  CantOpenDevice,
@@ -48,6 +48,8 @@ import { awaitsBleOn } from "./awaitsBleOn";
48
48
  import { decoratePromiseErrors, remapError, mapBleErrorToHwTransportError } from "./remapErrors";
49
49
  import { ReconnectionConfig } from "./types";
50
50
 
51
+ const LOG_TYPE = "ble-verbose";
52
+
51
53
  /**
52
54
  * This is potentially not needed anymore, to be checked if the bug is still
53
55
  * happening.
@@ -108,31 +110,49 @@ const bleManagerInstance = (): BleManager => {
108
110
  return _bleManager;
109
111
  };
110
112
 
111
- const clearDisconnectTimeout = (deviceId: string): void => {
113
+ const clearDisconnectTimeout = (deviceId: string, context?: TraceContext): void => {
112
114
  const cachedTransport = transportsCache[deviceId];
113
115
  if (cachedTransport && cachedTransport.disconnectTimeout) {
114
- log(TAG, "Clearing queued disconnect");
116
+ trace({ type: LOG_TYPE, message: "Clearing queued disconnect", context });
115
117
  clearTimeout(cachedTransport.disconnectTimeout);
116
118
  }
117
119
  };
118
120
 
119
- async function open(deviceOrId: Device | string, needsReconnect: boolean) {
121
+ /**
122
+ * Opens a BLE connection with a given device. Returns a Transport instance.
123
+ *
124
+ * @param deviceOrId
125
+ * @param needsReconnect
126
+ * @param timeoutMs TODO: to keep, used in a separate PR
127
+ * @param context Optional tracing/log context
128
+ * @returns A BleTransport instance
129
+ */
130
+ async function open(
131
+ deviceOrId: Device | string,
132
+ needsReconnect: boolean,
133
+ timeoutMs?: number,
134
+ context?: TraceContext,
135
+ ) {
136
+ const tracer = new LocalTracer(LOG_TYPE, context);
120
137
  let device: Device;
121
- log(TAG, `open with ${deviceOrId}`);
138
+ tracer.trace(`Opening ${deviceOrId}`, { needsReconnect });
122
139
 
123
140
  if (typeof deviceOrId === "string") {
124
141
  if (transportsCache[deviceOrId]) {
125
- log(TAG, "Transport in cache, using that.");
142
+ tracer.trace(`Transport in cache, using it`);
126
143
  clearDisconnectTimeout(deviceOrId);
144
+
145
+ // The cached transport probably has an older trace/log context
146
+ transportsCache[deviceOrId].setTraceContext(context);
127
147
  return transportsCache[deviceOrId];
128
148
  }
129
149
 
130
- log(TAG, `Tries to open device: ${deviceOrId}`);
150
+ tracer.trace(`Trying to open device: ${deviceOrId}`);
131
151
  await awaitsBleOn(bleManagerInstance());
132
152
 
133
153
  // Returns a list of known devices by their identifiers
134
154
  const devices = await bleManagerInstance().devices([deviceOrId]);
135
- log(TAG, `found ${devices.length} devices`);
155
+ tracer.trace(`Found ${devices.length} already known device(s) with given id`, { deviceOrId });
136
156
  [device] = devices;
137
157
 
138
158
  if (!device) {
@@ -143,18 +163,25 @@ async function open(deviceOrId: Device | string, needsReconnect: boolean) {
143
163
  getBluetoothServiceUuids(),
144
164
  );
145
165
  const connectedDevicesFiltered = connectedDevices.filter(d => d.id === deviceOrId);
146
- log(TAG, `found ${connectedDevicesFiltered.length} connected devices`);
166
+ tracer.trace(
167
+ `No known device with given id. Found ${connectedDevicesFiltered.length} devices from already connected devices`,
168
+ { deviceOrId },
169
+ );
147
170
  [device] = connectedDevicesFiltered;
148
171
  }
149
172
 
150
173
  if (!device) {
151
174
  // We still don't have a device, so we attempt to connect to it.
152
- log(TAG, `connectToDevice(${deviceOrId})`);
175
+ tracer.trace(`No known nor connected devices with given id. Trying to connect to device`, {
176
+ deviceOrId,
177
+ timeoutMs,
178
+ });
179
+
153
180
  // Nb ConnectionOptions dropped since it's not used internally by ble-plx.
154
181
  try {
155
182
  device = await bleManagerInstance().connectToDevice(deviceOrId, connectOptions);
156
183
  } catch (e: any) {
157
- log(TAG, `error code ${e.errorCode}`);
184
+ tracer.trace(`Error code: ${e.errorCode}`);
158
185
  if (e.errorCode === BleErrorCode.DeviceMTUChangeFailed) {
159
186
  // If the MTU update did not work, we try to connect without requesting for a specific MTU
160
187
  connectOptions = {};
@@ -174,19 +201,20 @@ async function open(deviceOrId: Device | string, needsReconnect: boolean) {
174
201
  }
175
202
 
176
203
  if (!(await device.isConnected())) {
177
- log(TAG, "not connected. connecting...");
204
+ tracer.trace(`Device found but not connected. connecting...`, { timeoutMs, connectOptions });
178
205
  try {
179
- await device.connect(connectOptions);
180
- } catch (e: any) {
181
- log("ble-verbose", `connect error - ${JSON.stringify(e)}`);
182
- if (e.errorCode === BleErrorCode.DeviceMTUChangeFailed) {
183
- log("ble-verbose", `device.mtu=${device.mtu}, reconnecting`);
206
+ await device.connect({ ...connectOptions });
207
+ } catch (error: any) {
208
+ tracer.trace(`Connect error`, { error });
209
+ if (error.errorCode === BleErrorCode.DeviceMTUChangeFailed) {
210
+ tracer.trace(`Device mtu=${device.mtu}, reconnecting`);
184
211
  connectOptions = {};
185
212
  await device.connect();
186
- } else if (e.iosErrorCode === 14 || e.reason === "Peer removed pairing information") {
187
- log("ble-verbose", "iOS broken pairing");
188
- log("ble-verbose", JSON.stringify(device));
189
- log("ble-verbose", JSON.stringify(bluetoothInfoCache[device.id]));
213
+ } else if (error.iosErrorCode === 14 || error.reason === "Peer removed pairing information") {
214
+ tracer.trace(`iOS broken pairing`, {
215
+ device,
216
+ bluetoothInfoCache: bluetoothInfoCache[device.id],
217
+ });
190
218
  const { deviceModel } = bluetoothInfoCache[device.id] || {};
191
219
  const { productName } = deviceModel || {};
192
220
  throw new PeerRemovedPairing(undefined, {
@@ -194,12 +222,14 @@ async function open(deviceOrId: Device | string, needsReconnect: boolean) {
194
222
  productName,
195
223
  });
196
224
  } else {
197
- throw remapError(e);
225
+ throw remapError(error);
198
226
  }
199
227
  }
200
228
  }
201
229
 
230
+ tracer.trace(`Device is connected now, getting services and characteristics`);
202
231
  await device.discoverAllServicesAndCharacteristics();
232
+
203
233
  let res: BluetoothInfos | undefined = retrieveInfos(device);
204
234
  let characteristics: Characteristic[] | undefined;
205
235
 
@@ -216,6 +246,7 @@ async function open(deviceOrId: Device | string, needsReconnect: boolean) {
216
246
  }
217
247
 
218
248
  if (!res) {
249
+ tracer.trace(`Service not found`);
219
250
  throw new TransportError("service not found", "BLEServiceNotFound");
220
251
  }
221
252
 
@@ -226,6 +257,7 @@ async function open(deviceOrId: Device | string, needsReconnect: boolean) {
226
257
  }
227
258
 
228
259
  if (!characteristics) {
260
+ tracer.trace(`Characteristics not found`);
229
261
  throw new TransportError("service not found", "BLEServiceNotFound");
230
262
  }
231
263
 
@@ -271,27 +303,33 @@ async function open(deviceOrId: Device | string, needsReconnect: boolean) {
271
303
  }
272
304
  }
273
305
 
274
- log(TAG, `device.mtu=${device.mtu}`);
275
- const notifyObservable = monitorCharacteristic(notifyC).pipe(
306
+ tracer.trace(`device.mtu=${device.mtu}`);
307
+ const notifyObservable = monitorCharacteristic(notifyC, context).pipe(
276
308
  catchError(e => {
277
309
  // LL-9033 fw 2.0.2 introduced this case, we silence the inner unhandled error.
278
310
  const msg = String(e);
279
- return msg.includes("notify change failed") ? of(new PairingFailed(msg)) : throwError(e);
311
+ return msg.includes("notify change failed")
312
+ ? of(new PairingFailed(msg))
313
+ : throwError(() => e);
280
314
  }),
281
315
  tap(value => {
282
316
  if (value instanceof PairingFailed) return;
283
- log("ble-frame", "<= " + value.toString("hex"));
317
+ trace({ type: "ble-frame", message: `<= ${value.toString("hex")}`, context });
284
318
  }),
285
319
  share(),
286
320
  );
287
321
  const notif = notifyObservable.subscribe();
288
- const transport = new BleTransport(device, writeC, writeCmdC, notifyObservable, deviceModel);
322
+
323
+ const transport = new BleTransport(device, writeC, writeCmdC, notifyObservable, deviceModel, {
324
+ context,
325
+ });
326
+ tracer.trace(`New BleTransport created`);
289
327
 
290
328
  // Keeping it as a comment for now but if no new bluetooth issues occur, we will be able to remove it
291
329
  // await transport.requestConnectionPriority("High");
292
330
  // eslint-disable-next-line prefer-const
293
331
  let disconnectedSub: Subscription;
294
- const onDisconnect = (e: BleError | null) => {
332
+ const onDisconnect = (error: BleError | null) => {
295
333
  transport.isConnected = false;
296
334
  transport.notYetDisconnected = false;
297
335
  notif.unsubscribe();
@@ -299,8 +337,11 @@ async function open(deviceOrId: Device | string, needsReconnect: boolean) {
299
337
 
300
338
  clearDisconnectTimeout(transport.id);
301
339
  delete transportsCache[transport.id];
302
- log(TAG, `BleTransport(${transport.id}) disconnected`);
303
- transport.emit("disconnect", e);
340
+ tracer.trace(
341
+ `On device disconnected callback: cleared cached transport for ${transport.id}, emitting Transport event "disconnect"`,
342
+ { reason: error },
343
+ );
344
+ transport.emit("disconnect", error);
304
345
  };
305
346
 
306
347
  // eslint-disable-next-line require-atomic-updates
@@ -325,7 +366,7 @@ async function open(deviceOrId: Device | string, needsReconnect: boolean) {
325
366
  if (afterMTUTime - beforeMTUTime < reconnectionConfig.pairingThreshold) {
326
367
  needsReconnect = false;
327
368
  } else if (deviceModel.id === DeviceModelId.stax) {
328
- log(TAG, "skipping needsReconnect for stax");
369
+ tracer.trace(`Skipping "needsReconnect" strategy for Stax`);
329
370
  needsReconnect = false;
330
371
  }
331
372
 
@@ -339,8 +380,8 @@ async function open(deviceOrId: Device | string, needsReconnect: boolean) {
339
380
  }
340
381
 
341
382
  if (needsReconnect) {
342
- log(TAG, "reconnecting");
343
- return open(device, false);
383
+ tracer.trace(`Reconnecting`);
384
+ return open(device, false, timeoutMs, context);
344
385
  }
345
386
 
346
387
  return transport;
@@ -351,7 +392,6 @@ async function open(deviceOrId: Device | string, needsReconnect: boolean) {
351
392
  * @example
352
393
  * import BleTransport from "@ledgerhq/react-native-hw-transport-ble";
353
394
  */
354
- const TAG = "ble-verbose";
355
395
  export default class BleTransport extends Transport {
356
396
  static disconnectTimeoutMs = 5000;
357
397
  /**
@@ -410,8 +450,12 @@ export default class BleTransport extends Transport {
410
450
  * @param observer Device is partial in order to avoid the live-common/this dep
411
451
  * @returns TransportSubscription
412
452
  */
413
- static listen(observer: TransportObserver<any, HwTransportError>): TransportSubscription {
414
- log(TAG, "listening for devices");
453
+ static listen(
454
+ observer: TransportObserver<any, HwTransportError>,
455
+ context?: TraceContext,
456
+ ): TransportSubscription {
457
+ const tracer = new LocalTracer(LOG_TYPE, context);
458
+ tracer.trace("Listening for devices ...");
415
459
 
416
460
  let unsubscribed: boolean;
417
461
 
@@ -421,7 +465,7 @@ export default class BleTransport extends Transport {
421
465
  const devices = await bleManagerInstance().connectedDevices(getBluetoothServiceUuids());
422
466
  if (unsubscribed) return;
423
467
  if (devices.length) {
424
- log(TAG, "disconnecting from devices");
468
+ tracer.trace("Disconnecting from all devices", { deviceCount: devices.length });
425
469
 
426
470
  await Promise.all(devices.map(d => BleTransport.disconnect(d.id).catch(() => {})));
427
471
  }
@@ -457,7 +501,7 @@ export default class BleTransport extends Transport {
457
501
  bleManagerInstance().stopDeviceScan();
458
502
  stateSub.remove();
459
503
 
460
- log(TAG, "done listening.");
504
+ tracer.trace("Done listening");
461
505
  };
462
506
 
463
507
  return {
@@ -466,21 +510,37 @@ export default class BleTransport extends Transport {
466
510
  }
467
511
 
468
512
  /**
469
- * Open a BLE transport
513
+ * Opens a BLE transport
514
+ *
470
515
  * @param {Device | string} deviceOrId
516
+ * @param timeoutMs TODO: to keep, used in a separate PR
517
+ * @param context An optional context object for log/tracing strategy
471
518
  */
472
- static async open(deviceOrId: Device | string): Promise<BleTransport> {
473
- return open(deviceOrId, true);
519
+ static async open(
520
+ deviceOrId: Device | string,
521
+ timeoutMs?: number,
522
+ context?: TraceContext,
523
+ ): Promise<BleTransport> {
524
+ return open(deviceOrId, true, timeoutMs, context);
474
525
  }
475
526
 
476
527
  /**
477
- * Exposed method from the ble-plx library
528
+ * Exposes method from the ble-plx library to disconnect a device
529
+ *
478
530
  * Disconnects from {@link Device} if it's connected or cancels pending connection.
479
531
  */
480
- static disconnect = async (id: DeviceId): Promise<void> => {
481
- log(TAG, `user disconnect(${id})`);
532
+ static disconnect = async (id: DeviceId, context?: TraceContext): Promise<void> => {
533
+ trace({
534
+ type: LOG_TYPE,
535
+ message: `Trying to disconnect device ${id})`,
536
+ context,
537
+ });
482
538
  await bleManagerInstance().cancelDeviceConnection(id);
483
- log(TAG, "disconnected");
539
+ trace({
540
+ type: LOG_TYPE,
541
+ message: `Device ${id} disconnected`,
542
+ context,
543
+ });
484
544
  };
485
545
 
486
546
  device: Device;
@@ -500,8 +560,9 @@ export default class BleTransport extends Transport {
500
560
  writeCmdCharacteristic: Characteristic | undefined,
501
561
  notifyObservable: Observable<any>,
502
562
  deviceModel: DeviceModel,
563
+ { context }: { context?: TraceContext } = {},
503
564
  ) {
504
- super();
565
+ super({ context, logType: LOG_TYPE });
505
566
  this.id = device.id;
506
567
  this.device = device;
507
568
  this.writeCharacteristic = writeCharacteristic;
@@ -509,33 +570,39 @@ export default class BleTransport extends Transport {
509
570
  this.notifyObservable = notifyObservable;
510
571
  this.deviceModel = deviceModel;
511
572
 
512
- log(TAG, `BleTransport(${String(this.id)}) new instance`);
513
573
  clearDisconnectTimeout(this.id);
574
+
575
+ this.tracer.trace(`New instance of BleTransport for device ${this.id}`);
514
576
  }
515
577
 
516
578
  /**
517
579
  * Send data to the device using a low level API.
518
580
  * It's recommended to use the "send" method for a higher level API.
581
+ *
519
582
  * @param {Buffer} apdu - The data to send.
520
583
  * @returns {Promise<Buffer>} A promise that resolves with the response data from the device.
521
584
  */
522
- exchange = (apdu: Buffer): Promise<any> =>
523
- this.exchangeAtomicImpl(async () => {
585
+ exchange = (apdu: Buffer): Promise<any> => {
586
+ const tracer = this.tracer.withUpdatedContext({
587
+ function: "exchange",
588
+ });
589
+ tracer.trace("Exchanging APDU ...");
590
+
591
+ return this.exchangeAtomicImpl(async () => {
524
592
  try {
525
593
  const msgIn = apdu.toString("hex");
526
- log("apdu", `=> ${msgIn}`);
594
+ tracer.withType("apdu").trace(`=> ${msgIn}`);
527
595
 
528
- const data = await merge(
529
- this.notifyObservable.pipe(receiveAPDU),
530
- sendAPDU(this.write, apdu, this.mtuSize),
531
- ).toPromise();
596
+ const data = await firstValueFrom(
597
+ merge(this.notifyObservable.pipe(receiveAPDU), sendAPDU(this.write, apdu, this.mtuSize)),
598
+ );
532
599
 
533
600
  const msgOut = data.toString("hex");
534
- log("apdu", `<= ${msgOut}`);
601
+ tracer.withType("apdu").trace(`<= ${msgOut}`);
535
602
 
536
603
  return data;
537
- } catch (e: any) {
538
- log("ble-error", "exchange got " + String(e));
604
+ } catch (error: any) {
605
+ tracer.withType("ble-error").trace(`Error while exchanging APDU`, { error });
539
606
 
540
607
  if (this.notYetDisconnected) {
541
608
  // in such case we will always disconnect because something is bad.
@@ -544,9 +611,14 @@ export default class BleTransport extends Transport {
544
611
  .catch(() => {}); // but we ignore if disconnect worked.
545
612
  }
546
613
 
547
- throw remapError(e);
614
+ const mappedError = remapError(error);
615
+ tracer.trace("Error while exchanging APDU, mapped and throws following error", {
616
+ mappedError,
617
+ });
618
+ throw mappedError;
548
619
  }
549
620
  });
621
+ };
550
622
 
551
623
  /**
552
624
  * Negotiate with the device the maximum transfer unit for the ble frames
@@ -554,33 +626,43 @@ export default class BleTransport extends Transport {
554
626
  */
555
627
  async inferMTU(): Promise<number> {
556
628
  let { mtu } = this.device;
629
+ this.tracer.trace(`Inferring MTU ...`, { currentDeviceMtu: mtu });
557
630
 
558
631
  await this.exchangeAtomicImpl(async () => {
559
632
  try {
560
- mtu = await merge(
561
- this.notifyObservable.pipe(
562
- tap(maybeError => {
563
- if (maybeError instanceof Error) throw maybeError;
564
- }),
565
- first(buffer => buffer.readUInt8(0) === 0x08),
566
- map(buffer => buffer.readUInt8(5)),
633
+ mtu = await firstValueFrom(
634
+ merge(
635
+ this.notifyObservable.pipe(
636
+ tap(maybeError => {
637
+ if (maybeError instanceof Error) throw maybeError;
638
+ }),
639
+ first(buffer => buffer.readUInt8(0) === 0x08),
640
+ map(buffer => buffer.readUInt8(5)),
641
+ ),
642
+ defer(() => from(this.write(Buffer.from([0x08, 0, 0, 0, 0])))).pipe(ignoreElements()),
567
643
  ),
568
- defer(() => from(this.write(Buffer.from([0x08, 0, 0, 0, 0])))).pipe(ignoreElements()),
569
- ).toPromise();
570
- } catch (e: any) {
571
- log("ble-error", "inferMTU got " + JSON.stringify(e));
644
+ );
645
+ } catch (error: any) {
646
+ this.tracer.withType("ble-error").trace("Error while inferring MTU", { mtu });
572
647
 
573
648
  await bleManagerInstance()
574
649
  .cancelDeviceConnection(this.id)
575
650
  .catch(() => {}); // but we ignore if disconnect worked.
576
651
 
577
- throw remapError(e);
652
+ const mappedError = remapError(error);
653
+ this.tracer.trace("Error while inferring APDU, mapped and throws following error", {
654
+ mappedError,
655
+ });
656
+ throw mappedError;
578
657
  }
579
658
  });
580
659
 
660
+ this.tracer.trace(`Successfully negotiated MTU with device`, {
661
+ mtu,
662
+ mtuSize: this.mtuSize,
663
+ });
581
664
  if (mtu > 20) {
582
665
  this.mtuSize = mtu;
583
- log(TAG, `BleTransport(${this.id}) mtu set to ${this.mtuSize}`);
584
666
  }
585
667
 
586
668
  return this.mtuSize;
@@ -607,19 +689,18 @@ export default class BleTransport extends Transport {
607
689
  * @param txid
608
690
  */
609
691
  write = async (buffer: Buffer, txid?: string | undefined): Promise<void> => {
610
- log("ble-frame", "=> " + buffer.toString("hex"));
611
- if (!this.writeCmdCharacteristic) {
612
- try {
692
+ try {
693
+ if (!this.writeCmdCharacteristic) {
613
694
  await this.writeCharacteristic.writeWithResponse(buffer.toString("base64"), txid);
614
- } catch (e: any) {
615
- throw new DisconnectedDeviceDuringOperation(e.message);
616
- }
617
- } else {
618
- try {
695
+ } else {
619
696
  await this.writeCmdCharacteristic.writeWithoutResponse(buffer.toString("base64"), txid);
620
- } catch (e: any) {
621
- throw new DisconnectedDeviceDuringOperation(e.message);
622
697
  }
698
+ this.tracer.withType("ble-frame").trace("=> " + buffer.toString("hex"));
699
+ } catch (error: unknown) {
700
+ this.tracer.trace("Error while writing APDU", { error });
701
+ throw new DisconnectedDeviceDuringOperation(
702
+ error instanceof Error ? error.message : `${error}`,
703
+ );
623
704
  }
624
705
  };
625
706
 
@@ -632,6 +713,8 @@ export default class BleTransport extends Transport {
632
713
  * @returns {Promise<void>}
633
714
  */
634
715
  async close(): Promise<void> {
716
+ this.tracer.trace("Closing, queuing a disconnect ...");
717
+
635
718
  let resolve: (value: void | PromiseLike<void>) => void;
636
719
  const disconnectPromise = new Promise<void>(innerResolve => {
637
720
  resolve = innerResolve;
@@ -639,12 +722,9 @@ export default class BleTransport extends Transport {
639
722
 
640
723
  clearDisconnectTimeout(this.id);
641
724
 
642
- log(TAG, "Queuing a disconnect");
643
-
644
725
  this.disconnectTimeout = setTimeout(() => {
645
- log(TAG, `Triggering a disconnect from ${this.id}`);
646
726
  if (this.isConnected) {
647
- BleTransport.disconnect(this.id)
727
+ BleTransport.disconnect(this.id, this.tracer.getContext())
648
728
  .catch(() => {})
649
729
  .finally(resolve);
650
730
  } else {
@@ -1,17 +1,28 @@
1
1
  import { Observable } from "rxjs";
2
2
  import { TransportError } from "@ledgerhq/errors";
3
3
  import type { Characteristic } from "./types";
4
- import { log } from "@ledgerhq/logs";
5
- export const monitorCharacteristic = (characteristic: Characteristic): Observable<Buffer> =>
4
+ import { LocalTracer, TraceContext } from "@ledgerhq/logs";
5
+
6
+ const LOG_TYPE = "ble-verbose";
7
+
8
+ export const monitorCharacteristic = (
9
+ characteristic: Characteristic,
10
+ context?: TraceContext,
11
+ ): Observable<Buffer> =>
6
12
  new Observable(o => {
7
- log("ble-verbose", "start monitor " + characteristic.uuid);
13
+ const tracer = new LocalTracer(LOG_TYPE, context);
14
+ tracer.trace(`Start monitoring BLE characteristics`, {
15
+ characteristicUuid: characteristic.uuid,
16
+ });
17
+
8
18
  const subscription = characteristic.monitor((error, c) => {
9
19
  if (error) {
10
- log("ble-verbose", "error monitor " + characteristic.uuid + ": " + error);
20
+ tracer.trace("Error while monitoring characteristics", { error });
11
21
  o.error(error);
12
22
  } else if (!c) {
23
+ tracer.trace("BLE monitored characteristic null value");
13
24
  o.error(
14
- new TransportError("characteristic monitor null value", "CharacteristicMonitorNull"),
25
+ new TransportError("Characteristic monitor null value", "CharacteristicMonitorNull"),
15
26
  );
16
27
  } else {
17
28
  try {
@@ -22,8 +33,8 @@ export const monitorCharacteristic = (characteristic: Characteristic): Observabl
22
33
  }
23
34
  }
24
35
  });
36
+
25
37
  return () => {
26
- log("ble-verbose", "end monitor " + characteristic.uuid);
27
38
  subscription.remove();
28
39
  };
29
40
  });