incyclist-devices 1.4.67 → 1.4.68

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.
@@ -9,6 +9,7 @@ interface BleDeviceConstructProps extends BleDeviceProps {
9
9
  declare type CommandQueueItem = {
10
10
  uuid: string;
11
11
  data: Buffer;
12
+ timeout: number;
12
13
  resolve: any;
13
14
  reject: any;
14
15
  };
@@ -26,6 +27,7 @@ export declare abstract class BleDevice extends BleDeviceClass {
26
27
  isInitialized: boolean;
27
28
  subscribedCharacteristics: string[];
28
29
  writeQueue: CommandQueueItem[];
30
+ workerIv: NodeJS.Timeout;
29
31
  constructor(props?: BleDeviceConstructProps);
30
32
  logEvent(event: any): void;
31
33
  setLogger(logger: EventLogger): void;
@@ -36,12 +38,16 @@ export declare abstract class BleDevice extends BleDeviceClass {
36
38
  waitForConnectFinished(timeout: any): Promise<unknown>;
37
39
  hasService(serviceUuid: any): boolean;
38
40
  init(): Promise<boolean>;
41
+ initDevice(): Promise<boolean>;
39
42
  connectPeripheral(peripheral: BlePeripheral): Promise<void>;
40
43
  subscribeAll(conn?: BlePeripheralConnector): Promise<void>;
41
44
  connect(props?: ConnectProps): Promise<boolean>;
42
45
  disconnect(): Promise<boolean>;
43
46
  abstract getProfile(): string;
44
47
  onData(characteristic: string, data: Buffer): void;
48
+ timeoutCheck(): void;
49
+ startWorker(): void;
50
+ stopWorker(): void;
45
51
  write(characteristicUuid: string, data: Buffer, withoutResponse?: boolean): Promise<ArrayBuffer>;
46
52
  read(characteristicUuid: string): Promise<Uint8Array>;
47
53
  getDeviceInfo(): Promise<BleDeviceInfo>;
@@ -27,6 +27,7 @@ class BleDevice extends ble_1.BleDeviceClass {
27
27
  this.subscribedCharacteristics = [];
28
28
  this.isInitialized = false;
29
29
  this.writeQueue = [];
30
+ this.workerIv = null;
30
31
  if (props.peripheral) {
31
32
  const { id, address, advertisement, state } = props.peripheral;
32
33
  this.peripheral = props.peripheral;
@@ -106,11 +107,17 @@ class BleDevice extends ble_1.BleDeviceClass {
106
107
  return this.services && this.services.find(s => s === serviceUuid || (0, ble_1.uuid)(serviceUuid)) !== undefined;
107
108
  }
108
109
  init() {
109
- if (this.isInitialized)
110
- return Promise.resolve(true);
110
+ return __awaiter(this, void 0, void 0, function* () {
111
+ if (this.isInitialized)
112
+ return Promise.resolve(true);
113
+ return yield this.initDevice();
114
+ });
115
+ }
116
+ initDevice() {
117
+ this.logEvent({ message: 'get device info' });
111
118
  return this.getDeviceInfo().then(() => {
112
119
  this.emit('deviceInfo', this.deviceInfo);
113
- this.logEvent(Object.assign({ message: 'ftms device init done' }, this.deviceInfo));
120
+ this.logEvent(Object.assign({ message: 'device init done' }, this.deviceInfo));
114
121
  this.isInitialized = true;
115
122
  return true;
116
123
  });
@@ -223,6 +230,9 @@ class BleDevice extends ble_1.BleDeviceClass {
223
230
  const { id, name, address } = this;
224
231
  this.logEvent({ message: 'disconnect requested', device: { id, name, address } });
225
232
  this.connectState.isDisconnecting = true;
233
+ if (this.workerIv) {
234
+ this.stopWorker();
235
+ }
226
236
  if (!this.connectState.isConnecting && !this.connectState.isConnected) {
227
237
  this.connectState.isDisconnecting = false;
228
238
  this.logEvent({ message: 'disconnect result: success', device: { id, name, address } });
@@ -254,11 +264,43 @@ class BleDevice extends ble_1.BleDeviceClass {
254
264
  }
255
265
  }
256
266
  }
267
+ timeoutCheck() {
268
+ const now = Date.now();
269
+ const updatedQueue = [];
270
+ let hasTimeout = false;
271
+ this.writeQueue.forEach(writeItem => {
272
+ if (writeItem.timeout && writeItem.timeout > now) {
273
+ if (writeItem.reject) {
274
+ hasTimeout = true;
275
+ writeItem.reject(new Error('timeout'));
276
+ }
277
+ }
278
+ else {
279
+ updatedQueue.push(writeItem);
280
+ }
281
+ });
282
+ if (hasTimeout)
283
+ this.writeQueue = updatedQueue;
284
+ }
285
+ startWorker() {
286
+ if (this.workerIv)
287
+ return;
288
+ this.workerIv = setInterval(() => { this.timeoutCheck(); }, 100);
289
+ }
290
+ stopWorker() {
291
+ if (!this.workerIv)
292
+ return;
293
+ clearInterval(this.workerIv);
294
+ this.workerIv = null;
295
+ }
257
296
  write(characteristicUuid, data, withoutResponse = false) {
258
297
  return __awaiter(this, void 0, void 0, function* () {
259
298
  try {
260
299
  const connector = this.ble.getConnector(this.peripheral);
261
300
  const isAlreadySubscribed = connector.isSubscribed(characteristicUuid);
301
+ if (!withoutResponse && !this.workerIv) {
302
+ this.startWorker();
303
+ }
262
304
  if (!withoutResponse && !isAlreadySubscribed) {
263
305
  const connector = this.ble.getConnector(this.peripheral);
264
306
  connector.removeAllListeners(characteristicUuid);
@@ -284,7 +326,7 @@ class BleDevice extends ble_1.BleDeviceClass {
284
326
  else {
285
327
  const writeId = this.writeQueue.length;
286
328
  let messageDeleted = false;
287
- this.writeQueue.push({ uuid: characteristicUuid.toLocaleLowerCase(), data, resolve, reject });
329
+ this.writeQueue.push({ uuid: characteristicUuid.toLocaleLowerCase(), data, timeout: Date.now() + 1000, resolve, reject });
288
330
  const to = setTimeout(() => {
289
331
  if (this.writeQueue.length > writeId && !messageDeleted)
290
332
  this.writeQueue.splice(writeId, 1);
@@ -590,14 +590,14 @@ class BleInterface extends ble_1.BleInterfaceClass {
590
590
  cntFound++;
591
591
  const existing = devicesProcessed.find(device => device.id === d.id && device.getProfile() === d.getProfile());
592
592
  if (!scanForDevice && cntFound > 0 && !existing) {
593
- this.logEvent({ message: `${opStr}: device found`, device: d.name, address: d.address, services: d.services.join(',') });
593
+ this.logEvent({ message: `${opStr}: device found`, device: d.name, profile: d.getProfile(), address: d.address, services: d.services.join(',') });
594
594
  this.addDeviceToCache(d, peripheral.state === 'connected');
595
595
  devicesProcessed.push(d);
596
596
  this.emit('device', d);
597
597
  return;
598
598
  }
599
599
  if (scanForDevice && cntFound > 0) {
600
- this.logEvent({ message: `${opStr}: device found`, device: d.name, address: d.address, services: d.services.join(',') });
600
+ this.logEvent({ message: `${opStr}: device found`, device: d.name, profile: d.getProfile(), address: d.address, services: d.services.join(',') });
601
601
  this.addDeviceToCache(d, peripheral.state === 'connected');
602
602
  devicesProcessed.push(d);
603
603
  this.emit('device', d);
package/lib/ble/fm.d.ts CHANGED
@@ -53,6 +53,7 @@ export default class BleFitnessMachineDevice extends BleDevice {
53
53
  wheelSize: number;
54
54
  constructor(props?: any);
55
55
  isMatching(characteristics: string[]): boolean;
56
+ subscribeWriteResponse(cuuid: string): Promise<void>;
56
57
  init(): Promise<boolean>;
57
58
  onDisconnect(): void;
58
59
  getProfile(): string;
package/lib/ble/fm.js CHANGED
@@ -104,35 +104,40 @@ class BleFitnessMachineDevice extends ble_device_1.BleDevice {
104
104
  const hasIndoorBike = characteristics.find(c => c === INDOOR_BIKE_DATA) !== undefined;
105
105
  return hasStatus && hasCP && hasIndoorBike;
106
106
  }
107
+ subscribeWriteResponse(cuuid) {
108
+ return __awaiter(this, void 0, void 0, function* () {
109
+ const connector = this.ble.getConnector(this.peripheral);
110
+ const isAlreadySubscribed = connector.isSubscribed(cuuid);
111
+ if (!isAlreadySubscribed) {
112
+ connector.removeAllListeners(cuuid);
113
+ let prev = undefined;
114
+ let prevTS = undefined;
115
+ connector.on(cuuid, (uuid, data) => {
116
+ const message = data.toString('hex');
117
+ if (prevTS && prev && message === prev && Date.now() - prevTS < 500) {
118
+ return;
119
+ }
120
+ prevTS = Date.now();
121
+ prev = message;
122
+ this.onData(uuid, data);
123
+ });
124
+ yield connector.subscribe(cuuid);
125
+ }
126
+ });
127
+ }
107
128
  init() {
108
129
  const _super = Object.create(null, {
109
- init: { get: () => super.init }
130
+ initDevice: { get: () => super.initDevice }
110
131
  });
111
132
  return __awaiter(this, void 0, void 0, function* () {
112
133
  try {
113
- const connector = this.ble.getConnector(this.peripheral);
114
- const isAlreadySubscribed = connector.isSubscribed(FTMS_CP);
115
- if (!isAlreadySubscribed) {
116
- connector.removeAllListeners(FTMS_CP);
117
- let prev = undefined;
118
- let prevTS = undefined;
119
- connector.on(FTMS_CP, (uuid, data) => {
120
- const message = data.toString('hex');
121
- if (prevTS && prev && message === prev && Date.now() - prevTS < 500) {
122
- return;
123
- }
124
- prevTS = Date.now();
125
- prev = message;
126
- this.onData(uuid, data);
127
- });
128
- yield connector.subscribe(FTMS_CP);
129
- }
130
- this.logEvent({ message: 'get device info' });
131
- yield _super.init.call(this);
134
+ yield this.subscribeWriteResponse(FTMS_CP);
135
+ yield _super.initDevice.call(this);
132
136
  yield this.getFitnessMachineFeatures();
133
137
  this.logEvent({ message: 'device info', deviceInfo: this.deviceInfo, features: this.features });
134
138
  }
135
139
  catch (err) {
140
+ this.logEvent({ message: 'error', fn: 'BleFitnessMachineDevice.init()', error: err.message || err, stack: err.stack });
136
141
  return Promise.resolve(false);
137
142
  }
138
143
  });
@@ -504,7 +509,8 @@ class FmAdapter extends Device_1.default {
504
509
  return (adapter.getName() === this.getName() && adapter.getProfile() === this.getProfile());
505
510
  }
506
511
  getProfile() {
507
- return 'Smart Trainer';
512
+ const profile = this.device ? this.device.getProfile() : undefined;
513
+ return profile || 'Smart Trainer';
508
514
  }
509
515
  getName() {
510
516
  return `${this.device.name}`;
package/lib/ble/tacx.js CHANGED
@@ -42,7 +42,7 @@ const TACX_FE_C_TX = '6e40fec3';
42
42
  const SYNC_BYTE = 0xA4;
43
43
  const DEFAULT_CHANNEL = 5;
44
44
  const ACKNOWLEDGED_DATA = 0x4F;
45
- const PROFILE_ID = 'Tacx FE-C over BLE';
45
+ const PROFILE_ID = 'Tacx SmartTrainer';
46
46
  const cwABike = {
47
47
  race: 0.35,
48
48
  triathlon: 0.29,
@@ -79,16 +79,16 @@ class TacxAdvancedFitnessMachineDevice extends fm_1.default {
79
79
  }
80
80
  init() {
81
81
  const _super = Object.create(null, {
82
- init: { get: () => super.init }
82
+ initDevice: { get: () => super.initDevice }
83
83
  });
84
84
  return __awaiter(this, void 0, void 0, function* () {
85
85
  try {
86
- this.logEvent({ message: 'get device info' });
87
- yield _super.init.call(this);
88
- this.logEvent({ message: 'device info', deviceInfo: this.deviceInfo, features: this.features });
86
+ yield _super.initDevice.call(this);
87
+ return true;
89
88
  }
90
89
  catch (err) {
91
- return Promise.resolve(false);
90
+ this.logEvent({ message: 'error', fn: 'TacxAdvancedFitnessMachineDevice.init()', error: err.message || err, stack: err.stack });
91
+ return false;
92
92
  }
93
93
  });
94
94
  }
@@ -62,33 +62,17 @@ class WahooAdvancedFitnessMachineDevice extends fm_1.default {
62
62
  }
63
63
  init() {
64
64
  const _super = Object.create(null, {
65
- init: { get: () => super.init }
65
+ initDevice: { get: () => super.initDevice }
66
66
  });
67
67
  return __awaiter(this, void 0, void 0, function* () {
68
68
  try {
69
- const connector = this.ble.getConnector(this.peripheral);
70
- const isAlreadySubscribed = connector.isSubscribed(WAHOO_ADVANCED_TRAINER_CP);
71
- if (!isAlreadySubscribed) {
72
- connector.removeAllListeners(WAHOO_ADVANCED_TRAINER_CP);
73
- let prev = undefined;
74
- let prevTS = undefined;
75
- connector.on(WAHOO_ADVANCED_TRAINER_CP, (uuid, data) => {
76
- const message = data.toString('hex');
77
- if (prevTS && prev && message === prev && Date.now() - prevTS < 500) {
78
- return;
79
- }
80
- prevTS = Date.now();
81
- prev = message;
82
- this.onData(uuid, data);
83
- });
84
- yield connector.subscribe(WAHOO_ADVANCED_TRAINER_CP);
85
- }
86
- this.logEvent({ message: 'get device info' });
87
- yield _super.init.call(this);
88
- this.logEvent({ message: 'device info', deviceInfo: this.deviceInfo, features: this.features });
69
+ yield this.subscribeWriteResponse(WAHOO_ADVANCED_TRAINER_CP);
70
+ yield _super.initDevice.call(this);
71
+ return true;
89
72
  }
90
73
  catch (err) {
91
- return Promise.resolve(false);
74
+ this.logEvent({ message: 'error', fn: 'WahooAdvancedFitnessMachineDevice.init()', error: err.message || err, stack: err.stack });
75
+ return false;
92
76
  }
93
77
  });
94
78
  }
@@ -195,7 +179,7 @@ class WahooAdvancedFitnessMachineDevice extends fm_1.default {
195
179
  const opcode = Buffer.alloc(1);
196
180
  opcode.writeUInt8(requestedOpCode, 0);
197
181
  const message = Buffer.concat([opcode, data]);
198
- const res = yield this.write(WAHOO_ADVANCED_FTMS, message);
182
+ const res = yield this.write(WAHOO_ADVANCED_TRAINER_CP, message);
199
183
  const responseData = Buffer.from(res);
200
184
  const result = responseData.readUInt8(0);
201
185
  this.logEvent({ message: 'response', opCode: requestedOpCode, response: responseData.toString('hex') });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "incyclist-devices",
3
- "version": "1.4.67",
3
+ "version": "1.4.68",
4
4
  "dependencies": {
5
5
  "@serialport/parser-byte-length": "^9.0.1",
6
6
  "@serialport/parser-delimiter": "^9.0.1",