incyclist-devices 2.1.19 → 2.1.22

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.
package/README.MD CHANGED
@@ -8,6 +8,9 @@ __ANT__
8
8
  - Smart Trainers (ANT+ FE)
9
9
  - Power Meters (ANT+PWR)
10
10
  - Heartrate Monitors (ANT+HR)
11
+ - Cadence Sensors (ANT+CAD)
12
+ - Speed Sensors (ANT+SPD)
13
+ - Speed + Cadence Sensors (ANT+SC)
11
14
 
12
15
  __BLE__
13
16
  - Smart Trainers (BLE FTMS)
@@ -3,7 +3,7 @@ import { IChannel, ISensor, Profile } from 'incyclist-ant-plus';
3
3
  import AntInterface from './interface';
4
4
  import IncyclistDevice from '../../base/adpater';
5
5
  import { AntDeviceProperties, AntDeviceSettings, LegacyProfile, BaseDeviceData, AdapterStartStatus } from '../types';
6
- import { IAdapter, IncyclistAdapterData, IncyclistBikeData } from '../../types';
6
+ import { IAdapter, IncyclistAdapterData, IncyclistBikeData, IncyclistCapability } from '../../types';
7
7
  export default class AntAdapter<TDeviceData extends BaseDeviceData> extends IncyclistDevice<AntDeviceProperties> {
8
8
  sensor: ISensor;
9
9
  data: IncyclistAdapterData;
@@ -29,6 +29,7 @@ export default class AntAdapter<TDeviceData extends BaseDeviceData> extends Incy
29
29
  constructor(settings: AntDeviceSettings, props?: AntDeviceProperties);
30
30
  getProfileName(): Profile;
31
31
  getLegacyProfileName(): LegacyProfile;
32
+ protected getStaticCapabilities(): Array<IncyclistCapability>;
32
33
  createSensor(settings: AntDeviceSettings): ISensor;
33
34
  isEqual(settings: AntDeviceSettings): boolean;
34
35
  getDefaultReconnectDelay(): number;
@@ -51,15 +51,22 @@ class AntAdapter extends adpater_1.default {
51
51
  if (this.isDebugEnabled()) {
52
52
  this.ant.setLogger(this);
53
53
  }
54
+ if (this.getStaticCapabilities())
55
+ this.capabilities = this.getStaticCapabilities();
54
56
  }
55
57
  getProfileName() {
58
+ var _a;
56
59
  const C = this.constructor;
57
- return C['ANT_PROFILE_NAME'];
60
+ return ((_a = this.sensor) === null || _a === void 0 ? void 0 : _a.getProfile()) || C['ANT_PROFILE_NAME'];
58
61
  }
59
62
  getLegacyProfileName() {
60
63
  const C = this.constructor;
61
64
  return C['INCYCLIST_PROFILE_NAME'];
62
65
  }
66
+ getStaticCapabilities() {
67
+ const C = this.constructor;
68
+ return C['CAPABILITIES'];
69
+ }
63
70
  createSensor(settings) {
64
71
  return sensor_factory_1.default.create(this.getProfileName(), Number(settings.deviceID));
65
72
  }
@@ -190,11 +197,10 @@ class AntAdapter extends adpater_1.default {
190
197
  return id.toString();
191
198
  }
192
199
  getName() {
193
- var _a;
194
200
  if (this.settings.name)
195
201
  return this.settings.name;
196
202
  const deviceID = this.getID();
197
- const profile = (_a = this.sensor) === null || _a === void 0 ? void 0 : _a.getProfile();
203
+ const profile = this.getProfileName();
198
204
  return `Ant+${profile} ${deviceID}`;
199
205
  }
200
206
  getUniqueName() {
@@ -1,10 +1,15 @@
1
1
  /// <reference types="node" />
2
2
  import EventEmitter from "events";
3
3
  import { EventLogger } from "gd-eventlog";
4
- import { IAntDevice, IChannel, ISensor } from "incyclist-ant-plus";
4
+ import { Channel, IAntDevice, IChannel, ISensor } from "incyclist-ant-plus";
5
5
  import { AntDeviceSettings, AntScanProps, AntInterfaceProps } from "../types";
6
6
  import { IncyclistInterface } from "../../types";
7
7
  import AntDeviceBinding from "./binding";
8
+ type ChannelUsage = 'scan' | 'sensor';
9
+ interface ChannelInfo {
10
+ channel: Channel;
11
+ usage: ChannelUsage;
12
+ }
8
13
  export default class AntInterface extends EventEmitter implements IncyclistInterface {
9
14
  static _instance: AntInterface;
10
15
  static INTERFACE_NAME: string;
@@ -22,6 +27,7 @@ export default class AntInterface extends EventEmitter implements IncyclistInter
22
27
  };
23
28
  protected props: AntInterfaceProps;
24
29
  protected logEnabled: boolean;
30
+ protected channelsInUse: Array<ChannelInfo>;
25
31
  constructor(props: AntInterfaceProps);
26
32
  getName(): string;
27
33
  getBinding(): typeof AntDeviceBinding;
@@ -42,5 +48,8 @@ export default class AntInterface extends EventEmitter implements IncyclistInter
42
48
  isScanning(): boolean;
43
49
  stopScan(): Promise<boolean>;
44
50
  startSensor(sensor: ISensor, onDeviceData: (data: any) => void): Promise<boolean>;
51
+ private blockChannel;
52
+ private unblockChannel;
45
53
  stopSensor(sensor: ISensor): Promise<boolean>;
46
54
  }
55
+ export {};
@@ -31,6 +31,7 @@ class AntInterface extends events_1.default {
31
31
  this.device = undefined;
32
32
  this.connected = false;
33
33
  this.connectPromise = null;
34
+ this.channelsInUse = [];
34
35
  this.logEnabled = props.log || true;
35
36
  const { binding, logger } = props;
36
37
  this.setLogger(logger || new gd_eventlog_1.EventLogger('Ant+'));
@@ -106,16 +107,32 @@ class AntInterface extends events_1.default {
106
107
  return __awaiter(this, void 0, void 0, function* () {
107
108
  this.logEvent({ message: 'ANT+ disconnecting ...' });
108
109
  let closed = false;
109
- if (this.device) {
110
- try {
111
- closed = yield this.device.close();
110
+ try {
111
+ let promises = [];
112
+ if (this.channelsInUse.length > 0) {
113
+ this.channelsInUse.forEach(c => {
114
+ if (c.usage === 'scan')
115
+ promises.push(this.stopScan());
116
+ else
117
+ promises.push(c.channel.stopAllSensors());
118
+ });
119
+ yield Promise.allSettled(promises);
120
+ yield (0, utils_1.sleep)(200);
121
+ }
122
+ if (this.device) {
123
+ try {
124
+ closed = yield this.device.close();
125
+ }
126
+ catch (_a) {
127
+ closed = false;
128
+ }
112
129
  }
113
- catch (_a) {
114
- closed = false;
130
+ else {
131
+ closed = true;
115
132
  }
116
133
  }
117
- else {
118
- closed = true;
134
+ catch (err) {
135
+ this.logEvent({ message: 'Error', fn: '', error: err.message, stack: err.stack });
119
136
  }
120
137
  this.logEvent({ message: 'ANT+ disconnected' });
121
138
  this.connectPromise = null;
@@ -205,10 +222,12 @@ class AntInterface extends events_1.default {
205
222
  addListeners(channel);
206
223
  try {
207
224
  const success = yield channel.startScanner();
225
+ this.blockChannel(channel, 'scan');
208
226
  this.logEvent({ message: 'scan started', success });
209
227
  }
210
228
  catch (err) {
211
229
  this.logEvent({ message: 'scan could not be started', error: err.message, stack: err.stack });
230
+ this.unblockChannel(channel);
212
231
  removeListeners(channel);
213
232
  return done(detected);
214
233
  }
@@ -261,10 +280,12 @@ class AntInterface extends events_1.default {
261
280
  this.logEvent({ message: 'stopping scan done ..' });
262
281
  return true;
263
282
  }
283
+ const channel = this.activeScan.channel;
264
284
  return new Promise(done => {
265
285
  this.activeScan.emitter.emit('stop');
266
286
  this.once('scan stopped', (res) => {
267
287
  this.logEvent({ message: 'stopping scan done ..' });
288
+ this.unblockChannel(channel);
268
289
  done(res);
269
290
  });
270
291
  });
@@ -281,6 +302,7 @@ class AntInterface extends events_1.default {
281
302
  channel = this.device.getChannel();
282
303
  if (!channel)
283
304
  return false;
305
+ this.blockChannel(channel, 'sensor');
284
306
  channel.setProps({ logger: this.logger });
285
307
  const onData = (profile, deviceID, data, tag) => {
286
308
  if (profile === sensor.getProfile() && deviceID === sensor.getDeviceID())
@@ -304,10 +326,19 @@ class AntInterface extends events_1.default {
304
326
  yield channel.stopSensor(sensor);
305
327
  }
306
328
  catch (_a) { }
329
+ this.unblockChannel(channel);
307
330
  return false;
308
331
  }
309
332
  });
310
333
  }
334
+ blockChannel(channel, usage) {
335
+ this.channelsInUse.push({ channel: channel, usage });
336
+ }
337
+ unblockChannel(channel) {
338
+ const idx = this.channelsInUse.findIndex(c => { var _a; return ((_a = c.channel) === null || _a === void 0 ? void 0 : _a.getChannelNo()) === channel.getChannelNo(); });
339
+ if (idx !== -1)
340
+ this.channelsInUse.splice(idx, 1);
341
+ }
311
342
  stopSensor(sensor) {
312
343
  return __awaiter(this, void 0, void 0, function* () {
313
344
  if (!this.isConnected()) {
@@ -328,6 +359,7 @@ class AntInterface extends events_1.default {
328
359
  channel.flush();
329
360
  channel.removeAllListeners('data');
330
361
  const stopped = yield channel.stopSensor(sensor);
362
+ this.unblockChannel(channel);
331
363
  return stopped;
332
364
  }
333
365
  catch (err) {
@@ -7,6 +7,8 @@ const profiles = [
7
7
  { profile: 'HR', Class: incyclist_ant_plus_2.HeartRateSensor },
8
8
  { profile: 'FE', Class: incyclist_ant_plus_2.FitnessEquipmentSensor },
9
9
  { profile: 'CAD', Class: incyclist_ant_plus_1.CadenceSensor },
10
+ { profile: 'SPD', Class: incyclist_ant_plus_1.SpeedSensor },
11
+ { profile: 'SC', Class: incyclist_ant_plus_1.SpeedCadenceSensor },
10
12
  ];
11
13
  class SensorFactory {
12
14
  static create(profile, deviceID) {
@@ -1,8 +1,11 @@
1
1
  import AntPwrAdapter from "./pwr";
2
2
  import AntFEAdapter from "./fe";
3
3
  import AntHrAdapter from "./hr";
4
+ import AntCadAdapter from "./cad";
4
5
  import AntAdapterFactory from "./factories/adapter-factory";
5
6
  import AntInterface from "./base/interface";
6
7
  import { AntInterfaceProps } from "./types";
8
+ import AntSpdAdapter from "./spd";
9
+ import AntScAdapter from "./sc";
7
10
  export { AntDeviceSettings, AntDeviceProperties, AntScanProps } from "./types";
8
- export { AntAdapterFactory, AntFEAdapter, AntHrAdapter, AntPwrAdapter, AntInterface, AntInterfaceProps };
11
+ export { AntAdapterFactory, AntFEAdapter, AntHrAdapter, AntPwrAdapter, AntScAdapter, AntSpdAdapter, AntCadAdapter, AntInterface, AntInterfaceProps };
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.AntInterface = exports.AntPwrAdapter = exports.AntHrAdapter = exports.AntFEAdapter = exports.AntAdapterFactory = void 0;
6
+ exports.AntInterface = exports.AntCadAdapter = exports.AntSpdAdapter = exports.AntScAdapter = exports.AntPwrAdapter = exports.AntHrAdapter = exports.AntFEAdapter = exports.AntAdapterFactory = void 0;
7
7
  const pwr_1 = __importDefault(require("./pwr"));
8
8
  exports.AntPwrAdapter = pwr_1.default;
9
9
  const fe_1 = __importDefault(require("./fe"));
@@ -11,12 +11,19 @@ exports.AntFEAdapter = fe_1.default;
11
11
  const hr_1 = __importDefault(require("./hr"));
12
12
  exports.AntHrAdapter = hr_1.default;
13
13
  const cad_1 = __importDefault(require("./cad"));
14
+ exports.AntCadAdapter = cad_1.default;
14
15
  const adapter_factory_1 = __importDefault(require("./factories/adapter-factory"));
15
16
  exports.AntAdapterFactory = adapter_factory_1.default;
16
17
  const interface_1 = __importDefault(require("./base/interface"));
17
18
  exports.AntInterface = interface_1.default;
19
+ const spd_1 = __importDefault(require("./spd"));
20
+ exports.AntSpdAdapter = spd_1.default;
21
+ const sc_1 = __importDefault(require("./sc"));
22
+ exports.AntScAdapter = sc_1.default;
18
23
  const af = adapter_factory_1.default.getInstance();
19
24
  af.register('PWR', 'Power Meter', pwr_1.default);
20
25
  af.register('HR', 'Heartrate Monitor', hr_1.default);
21
26
  af.register('FE', 'Smart Trainer', fe_1.default);
22
27
  af.register('CAD', 'Cadence Sensor', cad_1.default);
28
+ af.register('SPD', 'Speed Sensor', spd_1.default);
29
+ af.register('SC', 'Speed + Cadence Sensor', sc_1.default);
@@ -0,0 +1,11 @@
1
+ import { SpeedCadenceSensorState, Profile } from "incyclist-ant-plus";
2
+ import AntAdapter from "../base/adapter";
3
+ import { LegacyProfile } from "../types";
4
+ import { IncyclistCapability } from "../../types";
5
+ export default class AntSpdAdapter extends AntAdapter<SpeedCadenceSensorState> {
6
+ protected static INCYCLIST_PROFILE_NAME: LegacyProfile;
7
+ protected static ANT_PROFILE_NAME: Profile;
8
+ protected static CAPABILITIES: IncyclistCapability[];
9
+ mapToAdapterData(deviceData: SpeedCadenceSensorState): void;
10
+ hasData(): boolean;
11
+ }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const adapter_1 = __importDefault(require("../base/adapter"));
7
+ const types_1 = require("../../types");
8
+ class AntSpdAdapter extends adapter_1.default {
9
+ mapToAdapterData(deviceData) {
10
+ if (deviceData.CalculatedSpeed !== undefined) {
11
+ this.data.speed = deviceData.CalculatedSpeed;
12
+ this.data.timestamp = Date.now();
13
+ }
14
+ if (deviceData.CalculatedDistance !== undefined) {
15
+ this.data.deviceDistanceCounter = deviceData.CalculatedDistance;
16
+ }
17
+ if (deviceData.CalculatedCadence) {
18
+ this.data.cadence = deviceData.CalculatedCadence;
19
+ this.data.timestamp = Date.now();
20
+ }
21
+ }
22
+ hasData() {
23
+ return ((this.deviceData.CalculatedSpeed !== undefined && this.deviceData.CalculatedSpeed !== null) ||
24
+ (this.deviceData.CalculatedCadence !== undefined && this.deviceData.CalculatedCadence !== null));
25
+ }
26
+ }
27
+ AntSpdAdapter.INCYCLIST_PROFILE_NAME = 'Speed + Cadence Sensor';
28
+ AntSpdAdapter.ANT_PROFILE_NAME = 'SC';
29
+ AntSpdAdapter.CAPABILITIES = [types_1.IncyclistCapability.Speed, types_1.IncyclistCapability.Cadence];
30
+ exports.default = AntSpdAdapter;
@@ -0,0 +1,2 @@
1
+ import AntScAdapter from './adapter';
2
+ export default AntScAdapter;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const adapter_1 = __importDefault(require("./adapter"));
7
+ exports.default = adapter_1.default;
@@ -0,0 +1,11 @@
1
+ import { SpeedSensorState, Profile } from "incyclist-ant-plus";
2
+ import AntAdapter from "../base/adapter";
3
+ import { LegacyProfile } from "../types";
4
+ import { IncyclistCapability } from "../../types";
5
+ export default class AntSpdAdapter extends AntAdapter<SpeedSensorState> {
6
+ protected static INCYCLIST_PROFILE_NAME: LegacyProfile;
7
+ protected static ANT_PROFILE_NAME: Profile;
8
+ protected static CAPABILITIES: IncyclistCapability[];
9
+ mapToAdapterData(deviceData: SpeedSensorState): void;
10
+ hasData(): boolean;
11
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const adapter_1 = __importDefault(require("../base/adapter"));
7
+ const types_1 = require("../../types");
8
+ class AntSpdAdapter extends adapter_1.default {
9
+ mapToAdapterData(deviceData) {
10
+ if (deviceData.CalculatedSpeed !== undefined) {
11
+ this.data.speed = deviceData.CalculatedSpeed;
12
+ this.data.timestamp = Date.now();
13
+ }
14
+ if (deviceData.CalculatedDistance !== undefined) {
15
+ this.data.deviceDistanceCounter = deviceData.CalculatedDistance;
16
+ }
17
+ }
18
+ hasData() {
19
+ return this.deviceData.CalculatedSpeed !== undefined && this.deviceData.CalculatedSpeed !== null;
20
+ }
21
+ }
22
+ AntSpdAdapter.INCYCLIST_PROFILE_NAME = 'Speed Sensor';
23
+ AntSpdAdapter.ANT_PROFILE_NAME = 'SPD';
24
+ AntSpdAdapter.CAPABILITIES = [types_1.IncyclistCapability.Speed];
25
+ exports.default = AntSpdAdapter;
@@ -0,0 +1,2 @@
1
+ import AntSpdAdapter from './adapter';
2
+ export default AntSpdAdapter;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const adapter_1 = __importDefault(require("./adapter"));
7
+ exports.default = adapter_1.default;
@@ -19,6 +19,7 @@ const utils_1 = require("../../utils/utils");
19
19
  const adapter_factory_1 = __importDefault(require("../factories/adapter-factory"));
20
20
  const serial_scanner_1 = require("./serial-scanner");
21
21
  const DEFAULT_SCAN_TIMEOUT = 10000;
22
+ const MAX_PARALLEL_SCANS = 5;
22
23
  class SerialInterface extends events_1.default {
23
24
  static getInstance(props) {
24
25
  const { ifaceName, binding, logger } = props;
@@ -237,6 +238,10 @@ class SerialInterface extends events_1.default {
237
238
  return [];
238
239
  }
239
240
  this.logEvent({ message: 'scanning on ', interface: this.ifaceName, paths: paths.map(p => p.path).join(','), timeout });
241
+ let listReduced = false;
242
+ if (paths.length > MAX_PARALLEL_SCANS) {
243
+ paths = paths.filter((p, idx) => idx < MAX_PARALLEL_SCANS);
244
+ }
240
245
  const scanners = paths.map(p => new serial_scanner_1.SinglePathScanner(p.path, this, Object.assign(Object.assign({}, props), { logger: this.logger })));
241
246
  try {
242
247
  yield Promise.all(scanners.map(s => s.scan()
@@ -259,6 +264,9 @@ class SerialInterface extends events_1.default {
259
264
  clearTimeout(this.toScan);
260
265
  this.toScan = null;
261
266
  }
267
+ if (listReduced) {
268
+ paths.forEach(p => this.inUse.push(p.path));
269
+ }
262
270
  this.isScanning = false;
263
271
  this.logEvent({ message: 'scan finished on', interface: this.ifaceName, paths: paths.map(p => p.path), devices: detected.map(d => {
264
272
  const res = Object.assign({}, d);
@@ -67,17 +67,20 @@ class SinglePathScanner {
67
67
  }
68
68
  const adapterSettings = { interface: this.serial.getName(), host, port, protocol };
69
69
  const adapter = adapter_factory_1.default.getInstance().createInstance(adapterSettings);
70
- found = yield (adapter === null || adapter === void 0 ? void 0 : adapter.check());
71
- if (found) {
72
- this.isFound = true;
73
- const name = adapter.getName();
74
- resolve(Object.assign(Object.assign({}, adapterSettings), { name }));
70
+ if (this.isScanning) {
71
+ found = yield (adapter === null || adapter === void 0 ? void 0 : adapter.check());
72
+ if (found) {
73
+ this.isFound = true;
74
+ const name = adapter.getName();
75
+ resolve(Object.assign(Object.assign({}, adapterSettings), { name }));
76
+ }
77
+ yield adapter.close();
78
+ yield (0, utils_1.sleep)(1000);
75
79
  }
76
- yield (0, utils_1.sleep)(100);
77
80
  }
78
81
  catch (err) {
79
82
  this.logEvent({ message: 'error', fn: 'scan()', error: err.message || err, stack: err.stack });
80
- yield (0, utils_1.sleep)(100);
83
+ yield (0, utils_1.sleep)(2000);
81
84
  }
82
85
  }
83
86
  }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "incyclist-devices",
3
- "version": "2.1.19",
3
+ "version": "2.1.22",
4
4
  "dependencies": {
5
5
  "@serialport/bindings-interface": "^1.2.2",
6
6
  "@serialport/parser-byte-length": "^9.0.1",