incyclist-devices 2.3.0-beta.1 → 2.3.0-beta.11

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.
@@ -49,6 +49,7 @@ class BleInterface extends events_1.default {
49
49
  this.expectedServices = ['180d', '1818', '1826', '6e40fec1'];
50
50
  this.matching = [];
51
51
  this.connectedPeripherals = [];
52
+ this.connectAttemptCnt = 0;
52
53
  this.instanceId = ++instanceCount;
53
54
  this.props = props;
54
55
  this.logEnabled = props.log || true;
@@ -90,46 +91,51 @@ class BleInterface extends events_1.default {
90
91
  return false;
91
92
  }
92
93
  if (this.isConnecting()) {
93
- this.logEvent({ message: 'connect - already connecting' });
94
+ this.logEvent({ message: 'BLE connect - already connecting' });
94
95
  return this.connectTask.getPromise();
95
96
  }
96
97
  if (this.isConnected())
97
98
  return true;
98
- this.logEvent({ message: 'Ble connect request' });
99
+ this.logEvent({ message: 'BLE connect request' });
99
100
  this.connectTask = new task_1.InteruptableTask(this.connectBle(), {
100
- timeout: BLE_DEFAULT_CONNECT_TIMEOUT,
101
- name: 'connect',
101
+ timeout: this.getConnectTimeout(),
102
+ name: 'BLE connect',
102
103
  errorOnTimeout: false,
103
104
  log: this.logEvent.bind(this),
104
105
  });
105
- const success = yield this.connectTask.run();
106
+ const success = yield this.connectTask.run().catch(() => false);
106
107
  if (success) {
107
108
  this.startPeripheralScan();
108
109
  }
109
- this.expectedServices = factories_1.BleAdapterFactory.getInstance('ble').getAllSupportedServices();
110
110
  return success;
111
111
  });
112
112
  }
113
- disconnect() {
113
+ disconnect(cleanup) {
114
114
  return __awaiter(this, void 0, void 0, function* () {
115
+ var _a;
115
116
  if (!this.getBinding()) {
116
117
  return false;
117
118
  }
118
- if (!this.isConnected())
119
+ if (!this.isConnected() && !cleanup)
119
120
  return true;
120
- this.logEvent({ message: 'disconnect request' });
121
+ if (!cleanup)
122
+ this.logEvent({ message: 'disconnect request' });
123
+ this.emit('disconnect-request');
121
124
  yield this.stopPeripheralScan();
122
125
  const promises = this.connectedPeripherals.map(p => p.disconnect());
123
126
  yield Promise.allSettled(promises);
124
127
  this.connectedPeripherals = [];
125
- yield this.connectTask.stop();
128
+ if (this.isConnecting())
129
+ yield ((_a = this.connectTask) === null || _a === void 0 ? void 0 : _a.stop());
126
130
  this.getBinding().removeAllListeners();
131
+ this.connectAttemptCnt = 0;
132
+ this.emit('disconnect-done');
127
133
  return true;
128
134
  });
129
135
  }
130
136
  isConnected() {
131
137
  var _a;
132
- return ((_a = this.getBinding()) === null || _a === void 0 ? void 0 : _a.state) === 'poweredOn';
138
+ return this.connectAttemptCnt > 0 && ((_a = this.getBinding()) === null || _a === void 0 ? void 0 : _a.state) === 'poweredOn';
133
139
  }
134
140
  registerConnected(peripheral) {
135
141
  this.connectedPeripherals.push(peripheral);
@@ -200,11 +206,16 @@ class BleInterface extends events_1.default {
200
206
  if (peripheral)
201
207
  return Promise.resolve(peripheral);
202
208
  return new Promise((done) => {
209
+ const wasDiscovering = this.isDiscovering();
210
+ if (!wasDiscovering)
211
+ this.startPeripheralScan();
203
212
  const onDevice = (device) => {
204
213
  if (device.name === settings.name) {
205
214
  const peripheral = this.createPeripheralFromSettings(settings);
206
215
  if (peripheral) {
207
216
  this.off('device', onDevice);
217
+ if (!wasDiscovering)
218
+ this.stopPeripheralScan();
208
219
  done(peripheral);
209
220
  }
210
221
  }
@@ -216,7 +227,7 @@ class BleInterface extends events_1.default {
216
227
  const { peripheral } = service;
217
228
  if (peripheral.address === undefined || peripheral.address === '')
218
229
  peripheral.address = peripheral.id || peripheral.name;
219
- const protocol = this.getAdapterFactory().getProtocol(service.serviceUUIDs);
230
+ const protocol = this.getAdapterFactory().getProtocol(service.advertisement.serviceUuids);
220
231
  const { id, name, address } = (0, utils_1.getPeripheralInfo)(peripheral);
221
232
  return { interface: BleInterface.INTERFACE_NAME, protocol, id, name, address };
222
233
  }
@@ -228,6 +239,7 @@ class BleInterface extends events_1.default {
228
239
  }
229
240
  startPeripheralScan() {
230
241
  return __awaiter(this, arguments, void 0, function* (retry = false) {
242
+ this.expectedServices = this.getExpectedServices();
231
243
  if (!retry)
232
244
  this.logEvent({ message: 'starting peripheral discovery ...' });
233
245
  if (!this.isConnected() || this.isDiscovering()) {
@@ -254,9 +266,10 @@ class BleInterface extends events_1.default {
254
266
  return;
255
267
  this.logEvent({ message: 'stopping peripheral discovery ...' });
256
268
  this.discoverTask.stop();
257
- this.getBinding().off('discover', this.onDiscovered);
269
+ const ble = this.getBinding();
270
+ ble.off('discover', this.onDiscovered);
258
271
  return new Promise(done => {
259
- this.getBinding().stopScanning(() => {
272
+ ble.stopScanning(() => {
260
273
  done();
261
274
  });
262
275
  });
@@ -284,21 +297,6 @@ class BleInterface extends events_1.default {
284
297
  });
285
298
  });
286
299
  }
287
- pauseDiscovery() {
288
- this.getBinding().off('discover', this.onDiscovered);
289
- return new Promise(done => {
290
- try {
291
- this.getBinding().stopScanning();
292
- done();
293
- }
294
- catch (err) {
295
- done();
296
- }
297
- });
298
- }
299
- resumeDiscovery() {
300
- return this.discoverPeripherals();
301
- }
302
300
  onPeripheralFound(peripheral) {
303
301
  if (!this.isConnected() || !this.isDiscovering())
304
302
  return;
@@ -312,24 +310,33 @@ class BleInterface extends events_1.default {
312
310
  return;
313
311
  }
314
312
  if (announcement.serviceUUIDs.length === 0) {
315
- if (this.isCompleting(announcement)) {
316
- return;
317
- }
318
- this.addCompleting(announcement);
319
- setTimeout(() => {
320
- if (this.find(announcement)) {
321
- this.removeCompleting(announcement);
322
- return;
323
- }
324
- this.updateWithServices(announcement)
325
- .then(() => {
326
- if (this.isSupportedPeripheral(announcement))
327
- this.addService(announcement);
328
- });
329
- }, 1000);
313
+ return;
314
+ }
315
+ const isWahoo = this.checkForWahooEnhancement(announcement);
316
+ if (isWahoo) {
317
+ this.processWahooAnnouncement(announcement);
318
+ return;
330
319
  }
331
320
  this.addService(announcement);
332
321
  }
322
+ checkForWahooEnhancement(announcement) {
323
+ if (announcement.name.includes('KICKR')) {
324
+ const supported = announcement.serviceUUIDs.map(s => (0, utils_1.beautifyUUID)(s));
325
+ if (supported.length === 1 && supported[0] === '1818')
326
+ return true;
327
+ }
328
+ return false;
329
+ }
330
+ processWahooAnnouncement(announcement) {
331
+ if (this.isCompleting(announcement)) {
332
+ return;
333
+ }
334
+ this.updateWithServices(announcement)
335
+ .then(() => {
336
+ if (this.isSupportedPeripheral(announcement))
337
+ this.addService(announcement);
338
+ });
339
+ }
333
340
  buildAnnouncement(peripheral) {
334
341
  var _a;
335
342
  return {
@@ -359,7 +366,6 @@ class BleInterface extends events_1.default {
359
366
  const device = Object.assign({}, announcement);
360
367
  delete device.peripheral;
361
368
  const { peripheral } = announcement;
362
- let paused = false;
363
369
  try {
364
370
  peripheral.on('error', (err) => {
365
371
  peripheral.removeAllListeners();
@@ -378,14 +384,11 @@ class BleInterface extends events_1.default {
378
384
  const res = yield peripheral.discoverSomeServicesAndCharacteristicsAsync([], []);
379
385
  announcement.serviceUUIDs = res.services.map(s => s.uuid);
380
386
  }
381
- peripheral.removeAllListeners();
382
387
  }
383
388
  catch (err) {
384
389
  this.logEvent({ message: 'discover services failed', reason: err.message, device });
385
390
  }
386
- if (paused) {
387
- yield this.resumeDiscovery();
388
- }
391
+ peripheral === null || peripheral === void 0 ? void 0 : peripheral.removeAllListeners();
389
392
  return device.serviceUUIDs;
390
393
  });
391
394
  }
@@ -497,8 +500,10 @@ class BleInterface extends events_1.default {
497
500
  }
498
501
  connectBle() {
499
502
  return __awaiter(this, void 0, void 0, function* () {
503
+ this.connectAttemptCnt++;
500
504
  const state = this.getBinding().state;
501
505
  if (state === 'poweredOn') {
506
+ this.logEvent({ message: 'BLE connected' });
502
507
  return true;
503
508
  }
504
509
  const res = yield this.waitForBleConnected();
@@ -513,10 +518,7 @@ class BleInterface extends events_1.default {
513
518
  });
514
519
  this.getBinding().on('stateChange', (state) => {
515
520
  if (state === 'poweredOn') {
516
- this.logEvent({ message: 'Ble connect result: success' });
517
- this.getBinding().removeAllListeners('stateChange');
518
- this.getBinding().on('stateChange', this.onBleStateChange.bind(this));
519
- this.getBinding().on('error', console.log);
521
+ this.onConnected();
520
522
  return done(true);
521
523
  }
522
524
  else {
@@ -525,11 +527,40 @@ class BleInterface extends events_1.default {
525
527
  });
526
528
  });
527
529
  }
530
+ onError(err) {
531
+ this.logError(err, 'BLE connect');
532
+ }
533
+ onConnected() {
534
+ this.logEvent({ message: 'BLE connected' });
535
+ this.getBinding().removeAllListeners('error');
536
+ this.getBinding().removeAllListeners('stateChange');
537
+ this.getBinding().on('stateChange', this.onBleStateChange.bind(this));
538
+ this.getBinding().on('error', this.onError.bind(this));
539
+ }
540
+ onDisconnected() {
541
+ return __awaiter(this, void 0, void 0, function* () {
542
+ this.logEvent({ message: 'BLE Disconnected' });
543
+ yield this.disconnect(true);
544
+ this.getBinding().on('stateChange', this.onBleStateChange.bind(this));
545
+ this.getBinding().on('error', this.onError.bind(this));
546
+ });
547
+ }
528
548
  onBleStateChange(state) {
549
+ if (state !== 'poweredOn') {
550
+ this.onDisconnected();
551
+ }
552
+ else
553
+ this.onConnected();
529
554
  }
530
555
  getAdapterFactory() {
531
556
  return factories_1.BleAdapterFactory.getInstance('ble');
532
557
  }
558
+ getConnectTimeout() {
559
+ return BLE_DEFAULT_CONNECT_TIMEOUT;
560
+ }
561
+ getExpectedServices() {
562
+ return this.getAdapterFactory().getAllSupportedServices();
563
+ }
533
564
  logEvent(event) {
534
565
  if (this.logDisabled && event.message !== 'Error')
535
566
  return;
@@ -25,6 +25,7 @@ export declare class BlePeripheral implements IBlePeripheral {
25
25
  unsubscribe(characteristicUUID: string): Promise<boolean>;
26
26
  subscribeSelected(characteristics: string[], callback: (characteristicUuid: string, data: Buffer) => void): Promise<boolean>;
27
27
  discoverAllCharacteristics(): Promise<string[]>;
28
+ discoverSomeCharacteristics(characteristics: string[]): Promise<string[]>;
28
29
  subscribeAll(callback: (characteristicUuid: string, data: Buffer) => void): Promise<boolean>;
29
30
  unsubscribeAll(): Promise<boolean>;
30
31
  read(characteristicUUID: string): Promise<Buffer>;
@@ -29,10 +29,12 @@ class BlePeripheral {
29
29
  }
30
30
  connect() {
31
31
  return __awaiter(this, void 0, void 0, function* () {
32
+ if (this.isConnected())
33
+ return true;
32
34
  yield this.getPeripheral().connectAsync();
33
35
  this.ble.registerConnected(this);
34
36
  this.connected = true;
35
- return true;
37
+ return this.connected;
36
38
  });
37
39
  }
38
40
  disconnect() {
@@ -53,7 +55,7 @@ class BlePeripheral {
53
55
  yield this.getPeripheral().disconnectAsync();
54
56
  this.connected = false;
55
57
  this.disconnecting = false;
56
- return true;
58
+ return !this.connected;
57
59
  });
58
60
  }
59
61
  isConnected() {
@@ -68,10 +70,12 @@ class BlePeripheral {
68
70
  discoverServices() {
69
71
  return __awaiter(this, void 0, void 0, function* () {
70
72
  if (this.getPeripheral().discoverServicesAsync) {
73
+ this.logEvent({ message: 'discover services' });
71
74
  const services = yield this.getPeripheral().discoverServicesAsync([]);
72
75
  return services.map(s => s.uuid);
73
76
  }
74
77
  else {
78
+ this.logEvent({ message: 'discover services and characteristics' });
75
79
  const res = yield this.getPeripheral().discoverSomeServicesAndCharacteristicsAsync([], []);
76
80
  return res.services.map(s => s.uuid);
77
81
  }
@@ -92,8 +96,17 @@ class BlePeripheral {
92
96
  try {
93
97
  if (this.disconnecting || !this.connected)
94
98
  return false;
99
+ const onData = (data) => {
100
+ try {
101
+ callback(characteristicUUID, data);
102
+ }
103
+ catch (_a) { }
104
+ };
95
105
  const subscription = this.subscribed.find(s => s.uuid === characteristicUUID);
96
106
  if (subscription) {
107
+ const c = this.getRawCharacteristic(characteristicUUID);
108
+ if (c)
109
+ c.on('data', onData);
97
110
  return true;
98
111
  }
99
112
  const c = this.getRawCharacteristic(characteristicUUID);
@@ -114,12 +127,6 @@ class BlePeripheral {
114
127
  }
115
128
  else {
116
129
  if (callback) {
117
- const onData = (data) => {
118
- try {
119
- callback(characteristicUUID, data);
120
- }
121
- catch (_a) { }
122
- };
123
130
  this.subscribed.push({ uuid: characteristicUUID, callback: onData });
124
131
  c.on('data', onData);
125
132
  }
@@ -214,6 +221,24 @@ class BlePeripheral {
214
221
  }
215
222
  });
216
223
  }
224
+ discoverSomeCharacteristics(characteristics) {
225
+ return __awaiter(this, void 0, void 0, function* () {
226
+ try {
227
+ const target = characteristics.map(c => (0, utils_1.fullUUID)(c));
228
+ const res = yield this.getPeripheral().discoverSomeServicesAndCharacteristicsAsync([], target);
229
+ const found = [];
230
+ res.characteristics.forEach(c => {
231
+ this.characteristics[(0, utils_1.beautifyUUID)(c.uuid)] = c;
232
+ found.push(c.uuid);
233
+ });
234
+ return found;
235
+ }
236
+ catch (err) {
237
+ this.logEvent({ message: 'Error', fn: 'discoverAllCharacteristics', error: err.message, stack: err.stack });
238
+ return [];
239
+ }
240
+ });
241
+ }
217
242
  subscribeAll(callback) {
218
243
  return __awaiter(this, void 0, void 0, function* () {
219
244
  const characteristics = yield this.discoverAllCharacteristics();
@@ -20,7 +20,7 @@ export declare class TBleSensor extends EventEmitter implements IBleSensor {
20
20
  hasPeripheral(): boolean;
21
21
  startSensor(reconnect?: boolean): Promise<boolean>;
22
22
  protected getRequiredCharacteristics(): Array<string>;
23
- protected subscribe(): Promise<boolean>;
23
+ subscribe(): Promise<boolean>;
24
24
  stopSensor(): Promise<boolean>;
25
25
  reconnectSensor(): Promise<void>;
26
26
  reset(): void;
@@ -74,7 +74,7 @@ class TBleSensor extends events_1.default {
74
74
  return false;
75
75
  if (!reconnect)
76
76
  this.peripheral.onDisconnect(this.reconnectSensor.bind(this));
77
- return yield this.subscribe();
77
+ return true;
78
78
  });
79
79
  }
80
80
  getRequiredCharacteristics() {
@@ -101,11 +101,19 @@ class TBleSensor extends events_1.default {
101
101
  }
102
102
  reconnectSensor() {
103
103
  return __awaiter(this, void 0, void 0, function* () {
104
+ let connected = false;
105
+ let subscribed = false;
104
106
  let success = false;
105
107
  do {
106
- success = yield this.startSensor(true);
108
+ if (!connected) {
109
+ connected = yield this.startSensor(true);
110
+ }
111
+ if (connected && !subscribed) {
112
+ subscribed = yield this.subscribe();
113
+ }
114
+ success = connected && subscribed;
107
115
  if (!success) {
108
- yield (0, utils_1.sleep)(5000);
116
+ yield (0, utils_1.sleep)(1000);
109
117
  }
110
118
  } while (!success || this.stopRequested);
111
119
  });
@@ -119,10 +127,16 @@ class TBleSensor extends events_1.default {
119
127
  }
120
128
  read(characteristicUUID) {
121
129
  var _a;
130
+ if (!this.isConnected()) {
131
+ return Promise.reject(new Error('not connected'));
132
+ }
122
133
  return (_a = this.peripheral) === null || _a === void 0 ? void 0 : _a.read(characteristicUUID);
123
134
  }
124
135
  write(characteristicUUID, data, options) {
125
136
  var _a;
137
+ if (!this.isConnected()) {
138
+ return Promise.reject(new Error('not connected'));
139
+ }
126
140
  return (_a = this.peripheral) === null || _a === void 0 ? void 0 : _a.write(characteristicUUID, data, options);
127
141
  }
128
142
  onData(characteristic, data) {
@@ -7,8 +7,9 @@ import { IAdapter, IncyclistAdapterData, IncyclistBikeData } from '../../types';
7
7
  import { LegacyProfile } from '../../antv2/types';
8
8
  export default class BleFmAdapter extends BleAdapter<IndoorBikeData, BleFitnessMachineDevice> {
9
9
  protected static INCYCLIST_PROFILE_NAME: LegacyProfile;
10
- distanceInternal: number;
11
- connectPromise: Promise<boolean>;
10
+ protected distanceInternal: number;
11
+ protected connectPromise: Promise<boolean>;
12
+ protected requestControlRetryDelay: number;
12
13
  constructor(settings: BleDeviceSettings, props?: BleDeviceProperties);
13
14
  updateSensor(peripheral: IBlePeripheral): void;
14
15
  isSame(device: IAdapter): boolean;
@@ -20,11 +20,12 @@ const sensor_1 = __importDefault(require("./sensor"));
20
20
  const adapter_1 = __importDefault(require("../base/adapter"));
21
21
  const consts_1 = require("./consts");
22
22
  const types_1 = require("../../types");
23
- const task_1 = require("../../utils/task");
23
+ const utils_1 = require("../../utils/utils");
24
24
  class BleFmAdapter extends adapter_1.default {
25
25
  constructor(settings, props) {
26
26
  super(settings, props);
27
27
  this.distanceInternal = 0;
28
+ this.requestControlRetryDelay = 1000;
28
29
  this.logger = new gd_eventlog_1.EventLogger('BLE-FM');
29
30
  this.device = new sensor_1.default(this.getPeripheral(), { logger: this.logger });
30
31
  this.capabilities = [
@@ -117,6 +118,8 @@ class BleFmAdapter extends adapter_1.default {
117
118
  }
118
119
  initControl(_startProps) {
119
120
  return __awaiter(this, void 0, void 0, function* () {
121
+ if (!this.isStarting())
122
+ return;
120
123
  this.setConstants();
121
124
  yield this.establishControl();
122
125
  this.setConstants();
@@ -146,38 +149,30 @@ class BleFmAdapter extends adapter_1.default {
146
149
  return __awaiter(this, void 0, void 0, function* () {
147
150
  if (!this.isStarting())
148
151
  return false;
149
- let waitTask;
150
- let iv;
152
+ let hasControl = false;
153
+ let tryCnt = 0;
151
154
  const sensor = this.getComms();
152
- const wait = () => {
153
- const res = new Promise((resolve) => {
154
- iv = setInterval(() => __awaiter(this, void 0, void 0, function* () {
155
- if (!this.isStarting() || !(waitTask === null || waitTask === void 0 ? void 0 : waitTask.isRunning)) {
156
- resolve(false);
157
- clearInterval(iv);
158
- return;
155
+ return new Promise((resolve) => {
156
+ this.startTask.notifyOnStop(() => {
157
+ resolve(false);
158
+ });
159
+ const waitUntilControl = () => __awaiter(this, void 0, void 0, function* () {
160
+ while (!hasControl && this.isStarting()) {
161
+ if (tryCnt++ === 0) {
162
+ this.logEvent({ message: 'requesting control', device: this.getName(), interface: this.getInterface() });
159
163
  }
160
- const hasControl = yield sensor.requestControl();
164
+ hasControl = yield sensor.requestControl();
161
165
  if (hasControl) {
162
- clearInterval(iv);
163
- resolve(true);
166
+ this.logEvent({ message: 'control granted', device: this.getName(), interface: this.getInterface() });
167
+ resolve(this.isStarting());
164
168
  }
165
- else if (!this.isStarting() || !(waitTask === null || waitTask === void 0 ? void 0 : waitTask.isRunning)) {
166
- resolve(false);
167
- clearInterval(iv);
169
+ else {
170
+ yield (0, utils_1.sleep)(this.requestControlRetryDelay);
168
171
  }
169
- }), 1000);
172
+ }
170
173
  });
171
- return res;
172
- };
173
- waitTask = new task_1.InteruptableTask(wait(), {
174
- errorOnTimeout: false,
175
- timeout: 10000
174
+ waitUntilControl();
176
175
  });
177
- const hasControl = yield waitTask.run();
178
- clearInterval(iv);
179
- if (!hasControl && this.isStarting())
180
- throw new Error('could not establish control');
181
176
  });
182
177
  }
183
178
  sendInitialRequest() {
@@ -212,7 +207,7 @@ class BleFmAdapter extends adapter_1.default {
212
207
  try {
213
208
  const update = this.getCyclingMode().sendBikeUpdate(request);
214
209
  this.logEvent({ message: 'send bike update requested', profile: this.getProfile(), update, request });
215
- const device = this.device;
210
+ const device = this.getComms();
216
211
  if (update.slope !== undefined) {
217
212
  yield device.setSlope(update.slope);
218
213
  }
@@ -100,8 +100,6 @@ class BleFitnessMachineDevice extends sensor_1.TBleSensor {
100
100
  this.logEvent({ message: 'setTargetPower', power, skip: (this.data.targetPower !== undefined && this.data.targetPower === power) });
101
101
  if (this.data.targetPower !== undefined && this.data.targetPower === power)
102
102
  return true;
103
- if (!this.hasControl)
104
- return;
105
103
  const hasControl = yield this.requestControl();
106
104
  if (!hasControl) {
107
105
  this.logEvent({ message: 'setTargetPower failed', reason: 'control is disabled' });
@@ -111,15 +109,15 @@ class BleFitnessMachineDevice extends sensor_1.TBleSensor {
111
109
  data.writeUInt8(5, 0);
112
110
  data.writeInt16LE(Math.round(power), 1);
113
111
  const res = yield this.writeFtmsMessage(5, data);
112
+ if (res === 5) {
113
+ this.hasControl = false;
114
+ }
114
115
  return (res === 1);
115
116
  });
116
117
  }
117
118
  setSlope(slope) {
118
119
  return __awaiter(this, void 0, void 0, function* () {
119
120
  this.logEvent({ message: 'setSlope', slope });
120
- const hasControl = yield this.requestControl();
121
- if (!hasControl)
122
- return;
123
121
  const { windSpeed, crr, cw } = this;
124
122
  return yield this.setIndoorBikeSimulation(windSpeed, slope, crr, cw);
125
123
  });
@@ -331,6 +329,9 @@ class BleFitnessMachineDevice extends sensor_1.TBleSensor {
331
329
  data.writeUInt8(Math.round(crr * 10000), 5);
332
330
  data.writeUInt8(Math.round(cw * 100), 6);
333
331
  const res = yield this.writeFtmsMessage(17, data);
332
+ if (res === 5) {
333
+ this.hasControl = false;
334
+ }
334
335
  return (res === 1);
335
336
  });
336
337
  }
@@ -452,8 +452,14 @@ class TacxAdvancedFitnessMachineDevice extends sensor_1.default {
452
452
  sendMessage(message) {
453
453
  return __awaiter(this, void 0, void 0, function* () {
454
454
  this.logEvent({ message: 'write', characteristic: this.tacxTx, data: message.toString('hex') });
455
- yield this.write(this.tacxTx, message, { withoutResponse: true });
456
- return true;
455
+ try {
456
+ yield this.write(this.tacxTx, message, { withoutResponse: true });
457
+ return true;
458
+ }
459
+ catch (err) {
460
+ this.logEvent({ message: 'write failed', characteristic: this.tacxTx, reason: err.message });
461
+ return false;
462
+ }
457
463
  });
458
464
  }
459
465
  sendUserConfiguration(userWeight, bikeWeight, wheelDiameter, gearRatio) {
@@ -13,11 +13,17 @@ export interface BleBinding extends EventEmitter {
13
13
  state: BleInterfaceState;
14
14
  on(eventName: string | symbol, listener: (...args: any[]) => void): this;
15
15
  }
16
+ export interface BleRawAdvertisement {
17
+ address?: string;
18
+ localName?: string;
19
+ serviceUuids?: string[];
20
+ rssi?: number;
21
+ }
16
22
  export interface BleRawPeripheral extends EventEmitter {
17
23
  id?: string;
18
24
  address?: string;
19
25
  name?: string;
20
- services: [];
26
+ services: any[];
21
27
  advertisement: any;
22
28
  state: string;
23
29
  connectAsync(): Promise<void>;
package/lib/ble/utils.js CHANGED
@@ -6,6 +6,7 @@ exports.uuid = uuid;
6
6
  exports.matches = matches;
7
7
  exports.getPeripheralInfo = getPeripheralInfo;
8
8
  exports.getCharachteristicsInfo = getCharachteristicsInfo;
9
+ const gd_eventlog_1 = require("gd-eventlog");
9
10
  function mapLegacyProfile(profile) {
10
11
  switch (profile) {
11
12
  case 'Smart Trainer': return { profile: 'Smart Trainer', protocol: 'fm' };
@@ -74,7 +75,15 @@ const parseUUID = (str) => {
74
75
  };
75
76
  exports.parseUUID = parseUUID;
76
77
  const beautifyUUID = (str, withX = false) => {
77
- const uuid = (0, exports.parseUUID)(str);
78
+ let uuid;
79
+ try {
80
+ uuid = (0, exports.parseUUID)(str);
81
+ }
82
+ catch (err) {
83
+ const logger = new gd_eventlog_1.EventLogger('Incyclist');
84
+ logger.logEvent({ message: 'beautifyUUID error', uuid: str, error: err.message });
85
+ return str;
86
+ }
78
87
  const parts = [
79
88
  uuid.substring(0, 8),
80
89
  uuid.substring(8, 12),
@@ -57,7 +57,7 @@ export default class DirectConnectInterface extends EventEmitter implements IBle
57
57
  interface: string;
58
58
  name: string;
59
59
  }[];
60
- protected addService(service: MulticastDnsAnnouncement): void;
60
+ protected addService(service: MulticastDnsAnnouncement, source?: string): void;
61
61
  protected find(service: MulticastDnsAnnouncement): Announcement;
62
62
  protected getAll(): Announcement[];
63
63
  setDebug(enabled: boolean): void;