incyclist-devices 2.0.0-beta.1 → 2.0.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.
Files changed (114) hide show
  1. package/README.MD +238 -0
  2. package/lib/adapters.d.ts +1 -0
  3. package/lib/adapters.js +19 -0
  4. package/lib/antv2/adapter-factory.d.ts +8 -7
  5. package/lib/antv2/adapter-factory.js +4 -2
  6. package/lib/antv2/adapter.d.ts +3 -2
  7. package/lib/antv2/adapter.js +15 -4
  8. package/lib/antv2/ant-interface.d.ts +6 -2
  9. package/lib/antv2/ant-interface.js +27 -21
  10. package/lib/antv2/binding.d.ts +1 -1
  11. package/lib/antv2/binding.js +1 -1
  12. package/lib/antv2/fe/adapter.d.ts +12 -9
  13. package/lib/antv2/fe/adapter.js +67 -27
  14. package/lib/antv2/hr/adapter.d.ts +6 -5
  15. package/lib/antv2/hr/adapter.js +19 -16
  16. package/lib/antv2/index.d.ts +2 -2
  17. package/lib/antv2/pwr/adapter.d.ts +6 -4
  18. package/lib/antv2/pwr/adapter.js +24 -16
  19. package/lib/antv2/sensor-factory.d.ts +2 -2
  20. package/lib/antv2/types.d.ts +5 -2
  21. package/lib/antv2/types.js +3 -0
  22. package/lib/antv2/utils.d.ts +3 -0
  23. package/lib/antv2/utils.js +12 -1
  24. package/lib/base/adpater.d.ts +14 -2
  25. package/lib/base/adpater.js +43 -4
  26. package/lib/ble/adapter-factory.d.ts +18 -16
  27. package/lib/ble/adapter-factory.js +54 -45
  28. package/lib/ble/base/adapter.d.ts +53 -0
  29. package/lib/ble/{adapter.js → base/adapter.js} +111 -9
  30. package/lib/ble/base/comms-utils.d.ts +7 -0
  31. package/lib/ble/base/comms-utils.js +91 -0
  32. package/lib/ble/{ble-comms.d.ts → base/comms.d.ts} +27 -17
  33. package/lib/ble/{ble-comms.js → base/comms.js} +179 -53
  34. package/lib/ble/bindings/index.d.ts +2 -0
  35. package/lib/ble/bindings/index.js +8 -0
  36. package/lib/ble/bindings/linux.d.ts +15 -0
  37. package/lib/ble/bindings/linux.js +39 -0
  38. package/lib/ble/bindings/mock.d.ts +9 -0
  39. package/lib/ble/bindings/mock.js +108 -0
  40. package/lib/ble/bindings/types.d.ts +57 -0
  41. package/lib/ble/bindings/types.js +96 -0
  42. package/lib/ble/ble-interface.d.ts +34 -46
  43. package/lib/ble/ble-interface.js +242 -345
  44. package/lib/ble/ble-peripheral.d.ts +4 -2
  45. package/lib/ble/ble-peripheral.js +39 -8
  46. package/lib/ble/consts.d.ts +1 -0
  47. package/lib/ble/consts.js +2 -1
  48. package/lib/ble/cp/adapter.d.ts +1 -2
  49. package/lib/ble/cp/adapter.js +2 -15
  50. package/lib/ble/cp/comm.d.ts +8 -5
  51. package/lib/ble/cp/comm.js +12 -27
  52. package/lib/ble/elite/adapter.d.ts +1 -2
  53. package/lib/ble/elite/adapter.js +12 -19
  54. package/lib/ble/elite/comms.d.ts +8 -4
  55. package/lib/ble/elite/comms.js +12 -25
  56. package/lib/ble/fm/adapter.d.ts +3 -2
  57. package/lib/ble/fm/adapter.js +129 -70
  58. package/lib/ble/fm/comms.d.ts +8 -8
  59. package/lib/ble/fm/comms.js +33 -55
  60. package/lib/ble/fm/types.d.ts +5 -0
  61. package/lib/ble/hr/adapter.d.ts +1 -4
  62. package/lib/ble/hr/adapter.js +1 -18
  63. package/lib/ble/hr/comm.d.ts +6 -2
  64. package/lib/ble/hr/comm.js +6 -2
  65. package/lib/ble/hr/mock.d.ts +7 -0
  66. package/lib/ble/hr/mock.js +47 -0
  67. package/lib/ble/index.d.ts +2 -1
  68. package/lib/ble/index.js +5 -5
  69. package/lib/ble/peripheral-cache.d.ts +43 -0
  70. package/lib/ble/peripheral-cache.js +107 -0
  71. package/lib/ble/tacx/adapter.d.ts +1 -1
  72. package/lib/ble/tacx/adapter.js +20 -14
  73. package/lib/ble/tacx/comms.d.ts +6 -6
  74. package/lib/ble/tacx/comms.js +10 -43
  75. package/lib/ble/types.d.ts +54 -27
  76. package/lib/ble/types.js +0 -17
  77. package/lib/ble/utils.d.ts +15 -5
  78. package/lib/ble/utils.js +25 -66
  79. package/lib/ble/wahoo/adapter.d.ts +1 -1
  80. package/lib/ble/wahoo/adapter.js +12 -10
  81. package/lib/ble/wahoo/comms.d.ts +7 -6
  82. package/lib/ble/wahoo/comms.js +15 -17
  83. package/lib/index.d.ts +10 -7
  84. package/lib/index.js +21 -25
  85. package/lib/interfaces.d.ts +2 -1
  86. package/lib/interfaces.js +4 -0
  87. package/lib/modes/power-base.js +4 -0
  88. package/lib/serial/adapter.d.ts +5 -0
  89. package/lib/serial/adapter.js +19 -0
  90. package/lib/serial/bindings/tcp.d.ts +2 -1
  91. package/lib/serial/bindings/tcp.js +19 -5
  92. package/lib/serial/daum/DaumAdapter.d.ts +1 -1
  93. package/lib/serial/daum/DaumAdapter.js +16 -10
  94. package/lib/serial/daum/premium/adapter.d.ts +1 -0
  95. package/lib/serial/daum/premium/adapter.js +9 -2
  96. package/lib/serial/daum/premium/comms.js +10 -3
  97. package/lib/serial/daum/premium/mock.js +0 -1
  98. package/lib/serial/index.d.ts +3 -3
  99. package/lib/serial/index.js +2 -2
  100. package/lib/serial/kettler/ergo-racer/adapter.d.ts +1 -4
  101. package/lib/serial/kettler/ergo-racer/adapter.js +15 -39
  102. package/lib/serial/serial-interface.d.ts +3 -1
  103. package/lib/serial/serial-interface.js +43 -17
  104. package/lib/simulator/Simulator.d.ts +2 -0
  105. package/lib/simulator/Simulator.js +8 -5
  106. package/lib/types/adapter.d.ts +10 -3
  107. package/lib/types/device.d.ts +3 -0
  108. package/lib/types/interface.d.ts +7 -3
  109. package/package.json +3 -5
  110. package/lib/ble/adapter.d.ts +0 -41
  111. package/lib/ble/ble.d.ts +0 -57
  112. package/lib/ble/ble.js +0 -48
  113. package/lib/device.d.ts +0 -0
  114. package/lib/device.js +0 -0
@@ -37,13 +37,15 @@ class AntFEAdapter extends adapter_1.ControllableAntAdapter {
37
37
  this.dataMsgCount = 0;
38
38
  this.logger = new gd_eventlog_1.EventLogger('Ant+FE');
39
39
  this.isReconnecting = false;
40
+ this.startProps = {};
40
41
  this.capabilities = [
41
42
  capabilities_1.IncyclistCapability.Power, capabilities_1.IncyclistCapability.Speed, capabilities_1.IncyclistCapability.Cadence,
42
43
  capabilities_1.IncyclistCapability.Control
43
44
  ];
44
45
  }
45
46
  createSensor(settings) {
46
- return sensor_factory_1.default.create(AntFEAdapter.ANT_PROFILE_NAME, Number(settings.deviceID));
47
+ const sensor = sensor_factory_1.default.create(AntFEAdapter.ANT_PROFILE_NAME, Number(settings.deviceID));
48
+ return sensor;
47
49
  }
48
50
  getName() {
49
51
  if (this.settings.name)
@@ -51,14 +53,20 @@ class AntFEAdapter extends adapter_1.ControllableAntAdapter {
51
53
  const deviceID = this.sensor.getDeviceID();
52
54
  return `Ant+FE ${deviceID}`;
53
55
  }
54
- getDisplayName() {
55
- const { DeviceID, ManId, InstantaneousPower } = this.deviceData;
56
- const pwrStr = InstantaneousPower ? ` (${InstantaneousPower})` : '';
56
+ getUniqueName() {
57
+ if (this.settings.name)
58
+ return this.settings.name;
59
+ const { DeviceID, ManId } = this.deviceData;
57
60
  const brand = (0, utils_1.getBrand)(ManId);
58
61
  if (brand)
59
- return `${brand} FE ${DeviceID}${pwrStr}`;
62
+ return `${brand} FE ${DeviceID}`;
60
63
  else
61
- return `${this.getName()}${pwrStr}`;
64
+ return `${this.getName()}`;
65
+ }
66
+ getDisplayName() {
67
+ const { InstantaneousPower } = this.deviceData;
68
+ const pwrStr = InstantaneousPower ? ` (${InstantaneousPower})` : '';
69
+ return `${this.getUniqueName()}${pwrStr}`;
62
70
  }
63
71
  getSupportedCyclingModes() {
64
72
  return [ant_fe_st_mode_1.default, ant_fe_erg_mode_1.default, ant_fe_adv_st_mode_1.default];
@@ -73,17 +81,17 @@ class AntFEAdapter extends adapter_1.ControllableAntAdapter {
73
81
  });
74
82
  return logData;
75
83
  }
76
- sendUpdate(request) {
84
+ sendUpdate(request, forced = false) {
77
85
  return __awaiter(this, void 0, void 0, function* () {
78
- if (this.paused || this.isReconnecting)
86
+ if ((this.paused || this.isReconnecting) && !forced)
87
+ return;
88
+ let isReset = request.reset && Object.keys(request).length === 1;
89
+ const update = isReset ? this.getCyclingMode().getBikeInitRequest() : this.getCyclingMode().sendBikeUpdate(request);
90
+ if (!update)
79
91
  return;
80
- const update = this.getCyclingMode().sendBikeUpdate(request);
81
92
  this.logger.logEvent({ message: 'send bike update requested', update, request });
82
93
  try {
83
94
  const fe = this.sensor;
84
- const isReset = (!update || update.reset || Object.keys(update).length === 0);
85
- if (isReset)
86
- yield fe.sendTrackResistance(0);
87
95
  if (update.slope !== undefined) {
88
96
  yield fe.sendTrackResistance(update.slope);
89
97
  }
@@ -106,7 +114,7 @@ class AntFEAdapter extends adapter_1.ControllableAntAdapter {
106
114
  this.dataMsgCount++;
107
115
  this.lastDataTS = Date.now();
108
116
  super.onDeviceData(deviceData);
109
- if (!this.started || this.isStopped())
117
+ if (!this.started || this.isStopped() || this.paused)
110
118
  return;
111
119
  if (!this.ivDataTimeout && this.dataMsgCount > 0) {
112
120
  this.startDataTimeoutCheck();
@@ -114,21 +122,23 @@ class AntFEAdapter extends adapter_1.ControllableAntAdapter {
114
122
  try {
115
123
  const logData = this.getLogData(deviceData, ['PairedDevices', 'RawData']);
116
124
  this.logger.logEvent({ message: 'onDeviceData', data: logData });
117
- if (this.onDataFn && !this.paused) {
118
- if (!this.lastUpdate || (Date.now() - this.lastUpdate) > this.updateFrequency) {
119
- let incyclistData = this.mapData(deviceData);
120
- incyclistData = this.getCyclingMode().updateData(incyclistData);
121
- const data = this.transformData(incyclistData);
122
- this.onDataFn(data);
123
- this.lastUpdate = Date.now();
124
- }
125
- }
125
+ if (!this.canSendUpdate())
126
+ return;
127
+ let incyclistData = this.mapToCycleModeData(deviceData);
128
+ incyclistData = this.getCyclingMode().updateData(incyclistData);
129
+ this.data = this.transformData(incyclistData);
130
+ this.emitData(this.data);
126
131
  }
127
132
  catch (err) {
128
133
  this.logger.logEvent({ message: 'error', fn: 'onDeviceData()', error: err.message || err, stack: err.stack });
129
134
  }
130
135
  }
131
- mapData(deviceData) {
136
+ canSendUpdate() {
137
+ if (!this.hasDataListeners() || this.paused)
138
+ return false;
139
+ return super.canSendUpdate();
140
+ }
141
+ mapToCycleModeData(deviceData) {
132
142
  const data = {
133
143
  isPedalling: false,
134
144
  power: 0,
@@ -169,13 +179,16 @@ class AntFEAdapter extends adapter_1.ControllableAntAdapter {
169
179
  }
170
180
  start(props) {
171
181
  return __awaiter(this, void 0, void 0, function* () {
172
- if (this.started)
182
+ const wasPaused = this.paused;
183
+ this.paused = false;
184
+ if (this.started && !wasPaused) {
173
185
  return true;
186
+ }
174
187
  const connected = yield this.connect();
175
188
  if (!connected)
176
189
  throw new Error(`could not start device, reason:could not connect`);
177
190
  this.startProps = props;
178
- this.logEvent({ message: 'starting device -', props, isStarted: this.started, isReconnecting: this.isReconnecting });
191
+ this.logEvent({ message: 'starting device', props, isStarted: this.started, isReconnecting: this.isReconnecting });
179
192
  const opts = props || {};
180
193
  const { args = {}, user = {} } = opts;
181
194
  return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
@@ -218,7 +231,7 @@ class AntFEAdapter extends adapter_1.ControllableAntAdapter {
218
231
  }
219
232
  catch (_a) { }
220
233
  this.started = false;
221
- return reject(new Error(`could not start device, reason: ${err.message}`));
234
+ return reject(new Error('could not start device, reason:timeout'));
222
235
  }
223
236
  }
224
237
  status = { userSent: false, slopeSent: false };
@@ -236,7 +249,22 @@ class AntFEAdapter extends adapter_1.ControllableAntAdapter {
236
249
  const userWeight = args.userWeight || user.weight || adpater_1.DEFAULT_USER_WEIGHT;
237
250
  const bikeWeight = args.bikeWeight || defaultBikeWeight;
238
251
  status.userSent = status.userSent || (yield fe.sendUserConfiguration(userWeight, bikeWeight, args.wheelDiameter, args.gearRatio));
239
- status.slopeSent = status.slopeSent || (yield fe.sendTrackResistance(0.0));
252
+ if (!status.slopeSent) {
253
+ const startRequest = this.getCyclingMode().getBikeInitRequest();
254
+ if (startRequest) {
255
+ if (startRequest.targetPower !== undefined && startRequest.targetPower !== null) {
256
+ status.slopeSent = yield fe.sendTargetPower(startRequest.targetPower);
257
+ }
258
+ else if (startRequest.slope !== undefined && startRequest.slope !== null) {
259
+ status.slopeSent = yield fe.sendTrackResistance(startRequest.slope);
260
+ }
261
+ else
262
+ status.slopeSent = true;
263
+ }
264
+ else {
265
+ status.slopeSent = yield fe.sendTrackResistance(0.0);
266
+ }
267
+ }
240
268
  }
241
269
  catch (err) {
242
270
  this.logger.logEvent({ message: 'sending FE message error', error: err.message });
@@ -294,6 +322,18 @@ class AntFEAdapter extends adapter_1.ControllableAntAdapter {
294
322
  }
295
323
  });
296
324
  }
325
+ setCyclingMode(mode, settings) {
326
+ const modeChange = this.cyclingMode.getName() !== mode;
327
+ super.setCyclingMode(mode, settings);
328
+ console.log('~~~ setCyclingMode', mode, modeChange, this.started, this.stopped, this.paused, this.isReconnecting, this.data);
329
+ if (modeChange && this.started && !this.stopped) {
330
+ if (this.getCyclingMode() instanceof ant_fe_erg_mode_1.default) {
331
+ const power = this.data.power;
332
+ const request = power ? { targetPower: power } : this.getCyclingMode().getBikeInitRequest();
333
+ this.sendUpdate(request, true);
334
+ }
335
+ }
336
+ }
297
337
  }
298
338
  exports.default = AntFEAdapter;
299
339
  AntFEAdapter.INCYCLIST_PROFILE_NAME = 'Smart Trainer';
@@ -1,14 +1,15 @@
1
- import { HeartRateSensorState, ISensor } from "incyclist-ant-plus";
1
+ import { HeartRateSensorState, ISensor, Profile } from "incyclist-ant-plus";
2
2
  import AntAdapter from "../adapter";
3
- import { AntDeviceProperties, AntDeviceSettings } from "../types";
3
+ import { AntDeviceProperties, AntDeviceSettings, LegacyProfile } from "../types";
4
4
  export default class AntHrAdapter extends AntAdapter {
5
- static INCYCLIST_PROFILE_NAME: string;
6
- static ANT_PROFILE_NAME: string;
5
+ static INCYCLIST_PROFILE_NAME: LegacyProfile;
6
+ static ANT_PROFILE_NAME: Profile;
7
7
  constructor(settings: AntDeviceSettings, props?: AntDeviceProperties);
8
8
  createSensor(settings: AntDeviceSettings): ISensor;
9
9
  getName(): string;
10
+ getUniqueName(): string;
10
11
  getDisplayName(): string;
11
12
  onDeviceData(deviceData: HeartRateSensorState): void;
12
- updateData(data: any, deviceData: any): any;
13
+ mapData(deviceData: HeartRateSensorState): void;
13
14
  hasData(): boolean;
14
15
  }
@@ -30,14 +30,20 @@ class AntHrAdapter extends adapter_1.default {
30
30
  const deviceID = this.sensor.getDeviceID();
31
31
  return `Ant+HR ${deviceID}`;
32
32
  }
33
- getDisplayName() {
34
- const { DeviceID, ManId, ComputedHeartRate } = this.deviceData;
35
- const hrmStr = ComputedHeartRate ? ` (${ComputedHeartRate})` : '';
33
+ getUniqueName() {
34
+ if (this.settings.name)
35
+ return this.settings.name;
36
+ const { DeviceID, ManId } = this.deviceData;
36
37
  const brand = (0, utils_1.getBrand)(ManId);
37
38
  if (brand)
38
- return `${brand} Hrm ${DeviceID}${hrmStr}`;
39
+ return `${brand} HR ${DeviceID}`;
39
40
  else
40
- return `${this.getName()}${hrmStr}`;
41
+ return `${this.getName()}`;
42
+ }
43
+ getDisplayName() {
44
+ const { ComputedHeartRate } = this.deviceData;
45
+ const hrmStr = ComputedHeartRate ? ` (${ComputedHeartRate})` : '';
46
+ return `${this.getUniqueName()}${hrmStr}`;
41
47
  }
42
48
  onDeviceData(deviceData) {
43
49
  this.dataMsgCount++;
@@ -48,21 +54,18 @@ class AntHrAdapter extends adapter_1.default {
48
54
  if (!this.ivDataTimeout)
49
55
  this.startDataTimeoutCheck();
50
56
  try {
51
- if (this.onDataFn && !this.paused) {
52
- if (this.lastUpdate === undefined || (Date.now() - this.lastUpdate) > this.updateFrequency) {
53
- this.logEvent({ message: 'onDeviceData', data: deviceData });
54
- const data = this.updateData(this.data, deviceData);
55
- this.onDataFn(data);
56
- this.lastUpdate = Date.now();
57
- }
58
- }
57
+ if (!this.canSendUpdate())
58
+ return;
59
+ this.logEvent({ message: 'onDeviceData', data: deviceData });
60
+ this.mapData(deviceData);
61
+ this.emitData(this.data);
59
62
  }
60
63
  catch (err) {
61
64
  }
62
65
  }
63
- updateData(data, deviceData) {
64
- data.heartrate = deviceData.ComputedHeartRate;
65
- return data;
66
+ mapData(deviceData) {
67
+ if (deviceData.ComputedHeartRate)
68
+ this.data.heartrate = deviceData.ComputedHeartRate;
66
69
  }
67
70
  hasData() {
68
71
  return this.deviceData.ComputedHeartRate !== undefined && this.deviceData.ComputedHeartRate !== null;
@@ -2,6 +2,6 @@ import AntPwrAdapter from "./pwr";
2
2
  import AntFEAdapter from "./fe";
3
3
  import AntHrAdapter from "./hr";
4
4
  import AntAdapterFactory from "./adapter-factory";
5
- import AntInterface from "./ant-interface";
5
+ import AntInterface, { AntInterfaceProps } from "./ant-interface";
6
6
  import { AntDeviceSettings, AntScanProps } from "./types";
7
- export { AntAdapterFactory, AntFEAdapter, AntHrAdapter, AntPwrAdapter, AntDeviceSettings, AntScanProps, AntInterface };
7
+ export { AntAdapterFactory, AntFEAdapter, AntHrAdapter, AntPwrAdapter, AntDeviceSettings, AntScanProps, AntInterface, AntInterfaceProps };
@@ -1,20 +1,22 @@
1
- import { ISensor } from "incyclist-ant-plus";
1
+ import { ISensor, Profile } from "incyclist-ant-plus";
2
2
  import { ControllableAntAdapter } from "../adapter";
3
3
  import CyclingMode, { IncyclistBikeData } from '../../modes/cycling-mode';
4
- import { AntDeviceProperties, AntDeviceSettings } from "../types";
4
+ import { AntDeviceProperties, AntDeviceSettings, LegacyProfile } from "../types";
5
5
  import { DeviceData } from "../../types/data";
6
6
  export default class AntPwrAdapter extends ControllableAntAdapter {
7
- static INCYCLIST_PROFILE_NAME: string;
8
- static ANT_PROFILE_NAME: string;
7
+ static INCYCLIST_PROFILE_NAME: LegacyProfile;
8
+ static ANT_PROFILE_NAME: Profile;
9
9
  protected distanceInternal?: number;
10
10
  constructor(settings: AntDeviceSettings, props?: AntDeviceProperties);
11
11
  createSensor(settings: AntDeviceSettings): ISensor;
12
12
  getName(): string;
13
+ getUniqueName(): string;
13
14
  getDisplayName(): string;
14
15
  getDefaultCyclingMode(): CyclingMode;
15
16
  getSupportedCyclingModes(): any[];
16
17
  getLogData(data: any, excludeList: any): any;
17
18
  onDeviceData(deviceData: any): void;
19
+ canSendUpdate(): boolean;
18
20
  sendUpdate(request: any): void;
19
21
  mapData(deviceData: any): IncyclistBikeData;
20
22
  transformData(bikeData: IncyclistBikeData): DeviceData;
@@ -33,14 +33,20 @@ class AntPwrAdapter extends adapter_1.ControllableAntAdapter {
33
33
  const deviceID = this.sensor.getDeviceID();
34
34
  return `Ant+PWR ${deviceID}`;
35
35
  }
36
- getDisplayName() {
37
- const { DeviceID, ManId, Power } = this.deviceData;
38
- const pwrStr = Power ? ` (${Power})` : '';
36
+ getUniqueName() {
37
+ if (this.settings.name)
38
+ return this.settings.name;
39
+ const { DeviceID, ManId } = this.deviceData;
39
40
  const brand = (0, utils_1.getBrand)(ManId);
40
41
  if (brand)
41
- return `${brand} PWR ${DeviceID}${pwrStr}`;
42
+ return `${brand} PWR ${DeviceID}`;
42
43
  else
43
- return `${this.getName()}${pwrStr}`;
44
+ return `${this.getName()}`;
45
+ }
46
+ getDisplayName() {
47
+ const { Power } = this.deviceData;
48
+ const pwrStr = Power ? ` (${Power})` : '';
49
+ return `${this.getUniqueName()}${pwrStr}`;
44
50
  }
45
51
  getDefaultCyclingMode() {
46
52
  return new power_meter_1.default(this);
@@ -64,21 +70,23 @@ class AntPwrAdapter extends adapter_1.ControllableAntAdapter {
64
70
  if (!this.ivDataTimeout)
65
71
  this.startDataTimeoutCheck();
66
72
  try {
67
- if (this.onDataFn && !this.paused) {
68
- if (!this.lastUpdate || (Date.now() - this.lastUpdate) > this.updateFrequency) {
69
- const logData = this.getLogData(deviceData, ['PairedDevices', 'RawData']);
70
- this.logger.logEvent({ message: 'onDeviceData', data: logData });
71
- let incyclistData = this.mapData(deviceData);
72
- incyclistData = this.getCyclingMode().updateData(incyclistData);
73
- const data = this.transformData(incyclistData);
74
- this.onDataFn(data);
75
- this.lastUpdate = Date.now();
76
- }
77
- }
73
+ if (!this.canSendUpdate())
74
+ return;
75
+ const logData = this.getLogData(deviceData, ['PairedDevices', 'RawData']);
76
+ this.logger.logEvent({ message: 'onDeviceData', data: logData });
77
+ let incyclistData = this.mapData(deviceData);
78
+ incyclistData = this.getCyclingMode().updateData(incyclistData);
79
+ const data = this.transformData(incyclistData);
80
+ this.emitData(data);
78
81
  }
79
82
  catch (err) {
80
83
  }
81
84
  }
85
+ canSendUpdate() {
86
+ if (!this.hasDataListeners() || this.paused)
87
+ return false;
88
+ return super.canSendUpdate();
89
+ }
82
90
  sendUpdate(request) {
83
91
  if (this.isPaused())
84
92
  return;
@@ -1,5 +1,5 @@
1
- import { ISensor } from "incyclist-ant-plus";
1
+ import { ISensor, Profile } from "incyclist-ant-plus";
2
2
  export default class SensorFactory {
3
- static create(profile: string, deviceID?: number): ISensor;
3
+ static create(profile: Profile, deviceID?: number): ISensor;
4
4
  static createAll(): ISensor[];
5
5
  }
@@ -1,14 +1,17 @@
1
+ import { Profile } from 'incyclist-ant-plus';
1
2
  import IncyclistDevice from '../base/adpater';
2
3
  import { DeviceProperties, DeviceSettings, IncyclistScanProps } from '../types/device';
3
4
  export interface AntDeviceSettings extends DeviceSettings {
4
5
  deviceID?: string;
5
- profile: string;
6
+ profile: Profile | LegacyProfile;
6
7
  protocol?: string;
7
8
  }
9
+ export type LegacyProfile = 'Heartrate Monitor' | 'Power Meter' | 'Smart Trainer' | 'Speed Sensor' | 'Cadence Sensor' | 'Speed + Cadence Sensor';
10
+ export declare const isLegacyProfile: (o: unknown) => boolean;
8
11
  export type DeviceFoundCallback = (device: IncyclistDevice, protocol: string) => void;
9
12
  export type ScanFinishedCallback = (id: number) => void;
10
13
  export interface AntScanProps extends IncyclistScanProps {
11
- profiles?: string[];
14
+ profiles?: Profile[];
12
15
  id?: number;
13
16
  onDeviceFound?: DeviceFoundCallback;
14
17
  onScanFinished?: ScanFinishedCallback;
@@ -1,2 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isLegacyProfile = void 0;
4
+ const isLegacyProfile = (o) => o === 'Heartrate Monitor' || o === 'Power Meter' || o === 'Smart Trainer' || o === 'Speed Sensor' || o === 'Cadence Sensor' || o === 'Speed + Cadence Sensor';
5
+ exports.isLegacyProfile = isLegacyProfile;
@@ -1 +1,4 @@
1
+ import { Profile } from "incyclist-ant-plus";
2
+ import { LegacyProfile } from "./types";
1
3
  export declare const getBrand: (manId: number) => string;
4
+ export declare const mapLegacyProfile: (legacy: LegacyProfile) => Profile;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getBrand = void 0;
3
+ exports.mapLegacyProfile = exports.getBrand = void 0;
4
4
  const brands = [
5
5
  'Garmin,1',
6
6
  'garmin_fr405_antfs,2',
@@ -179,3 +179,14 @@ const getBrand = (manId) => {
179
179
  return;
180
180
  };
181
181
  exports.getBrand = getBrand;
182
+ const mapLegacyProfile = (legacy) => {
183
+ switch (legacy) {
184
+ case 'Heartrate Monitor': return 'HR';
185
+ case 'Power Meter': return 'PWR';
186
+ case 'Smart Trainer': return 'FE';
187
+ case 'Cadence Sensor': return 'CAD';
188
+ case 'Speed Sensor': return 'SPD';
189
+ case 'Speed + Cadence Sensor': return 'SC';
190
+ }
191
+ };
192
+ exports.mapLegacyProfile = mapLegacyProfile;
@@ -1,11 +1,12 @@
1
1
  /// <reference types="node" />
2
- import { EventEmitter } from "stream";
3
2
  import CyclingMode from "../modes/cycling-mode";
4
3
  import { DeviceProperties, DeviceSettings } from "../types/device";
5
4
  import { Bike, IncyclistDeviceAdapter, OnDeviceDataCallback } from '../types/adapter';
6
5
  import { User } from "../types/user";
7
6
  import { IncyclistCapability } from "../types/capabilities";
8
7
  import { EventLogger } from "gd-eventlog";
8
+ import { DeviceData } from "../types/data";
9
+ import EventEmitter from "events";
9
10
  export declare const DEFAULT_BIKE_WEIGHT = 10;
10
11
  export declare const DEFAULT_USER_WEIGHT = 75;
11
12
  export declare const DEFAULT_PROPS: DeviceProperties;
@@ -13,6 +14,8 @@ export default class IncyclistDevice extends EventEmitter implements IncyclistDe
13
14
  onDataFn: OnDeviceDataCallback;
14
15
  settings: DeviceSettings;
15
16
  props: DeviceProperties;
17
+ lastUpdate?: number;
18
+ updateFrequency: number;
16
19
  capabilities: IncyclistCapability[];
17
20
  protected logger: EventLogger;
18
21
  started: boolean;
@@ -22,30 +25,39 @@ export default class IncyclistDevice extends EventEmitter implements IncyclistDe
22
25
  connect(): Promise<boolean>;
23
26
  close(): Promise<boolean>;
24
27
  check(): Promise<boolean>;
25
- isEqual(settings: DeviceSettings): void;
28
+ isControllable(): boolean;
29
+ isEqual(settings: DeviceSettings): boolean;
26
30
  getCapabilities(): IncyclistCapability[];
27
31
  hasCapability(capability: IncyclistCapability): boolean;
32
+ addCapability(capability: IncyclistCapability): void;
28
33
  update(): void;
29
34
  start(props?: DeviceProperties): Promise<boolean>;
30
35
  stop(): Promise<boolean>;
31
36
  pause(): Promise<boolean>;
32
37
  resume(): Promise<boolean>;
33
38
  logEvent(event: any): void;
39
+ getMaxUpdateFrequency(): number;
40
+ setMaxUpdateFrequency(value: number): void;
34
41
  sendUpdate(request: any): void;
35
42
  getID(): string;
36
43
  getDisplayName(): string;
37
44
  getName(): string;
45
+ getUniqueName(): string;
38
46
  getSettings(): DeviceSettings;
39
47
  getInterface(): string;
40
48
  onData(callback: OnDeviceDataCallback): void;
49
+ canSendUpdate(): boolean;
50
+ emitData(data: DeviceData): void;
41
51
  isStopped(): boolean;
42
52
  isStarted(): boolean;
43
53
  isPaused(): boolean;
54
+ hasDataListeners(): boolean | OnDeviceDataCallback;
44
55
  }
45
56
  export declare class ControllableDevice extends IncyclistDevice implements Bike {
46
57
  cyclingMode: CyclingMode;
47
58
  user?: User;
48
59
  constructor(settings: DeviceSettings, props?: DeviceProperties);
60
+ isControllable(): boolean;
49
61
  setUser(user: User): void;
50
62
  setBikeProps(props: DeviceProperties): void;
51
63
  getWeight(): number;
@@ -8,16 +8,19 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
11
14
  Object.defineProperty(exports, "__esModule", { value: true });
12
15
  exports.ControllableDevice = exports.DEFAULT_PROPS = exports.DEFAULT_USER_WEIGHT = exports.DEFAULT_BIKE_WEIGHT = void 0;
13
- const stream_1 = require("stream");
16
+ const events_1 = __importDefault(require("events"));
14
17
  exports.DEFAULT_BIKE_WEIGHT = 10;
15
18
  exports.DEFAULT_USER_WEIGHT = 75;
16
19
  exports.DEFAULT_PROPS = {
17
20
  userWeight: exports.DEFAULT_USER_WEIGHT,
18
21
  bikeWeight: exports.DEFAULT_BIKE_WEIGHT
19
22
  };
20
- class IncyclistDevice extends stream_1.EventEmitter {
23
+ class IncyclistDevice extends events_1.default {
21
24
  constructor(settings, props) {
22
25
  super();
23
26
  this.onDataFn = undefined;
@@ -31,11 +34,18 @@ class IncyclistDevice extends stream_1.EventEmitter {
31
34
  connect() { throw new Error('not implemented'); }
32
35
  close() { throw new Error('not implemented'); }
33
36
  check() { throw new Error("Method not implemented."); }
37
+ isControllable() {
38
+ return false;
39
+ }
34
40
  isEqual(settings) { throw new Error("Method not implemented."); }
35
41
  getCapabilities() { return this.capabilities; }
36
42
  hasCapability(capability) {
37
43
  return this.capabilities.find(c => c === capability) !== undefined;
38
44
  }
45
+ addCapability(capability) {
46
+ if (!this.capabilities.includes(capability))
47
+ this.capabilities.push(capability);
48
+ }
39
49
  update() { throw new Error("Method not implemented."); }
40
50
  start(props) { throw new Error("Method not implemented."); }
41
51
  stop() { throw new Error("Method not implemented."); }
@@ -52,10 +62,16 @@ class IncyclistDevice extends stream_1.EventEmitter {
52
62
  });
53
63
  }
54
64
  logEvent(event) {
55
- if (!this.logger)
65
+ if (!this.logger || this.paused)
56
66
  return;
57
67
  this.logger.logEvent(event);
58
68
  }
69
+ getMaxUpdateFrequency() {
70
+ return this.updateFrequency;
71
+ }
72
+ setMaxUpdateFrequency(value) {
73
+ this.updateFrequency = value;
74
+ }
59
75
  sendUpdate(request) { throw new Error("Method not implemented."); }
60
76
  getID() { throw new Error('not implemented'); }
61
77
  getDisplayName() {
@@ -64,6 +80,9 @@ class IncyclistDevice extends stream_1.EventEmitter {
64
80
  getName() {
65
81
  return this.settings.name;
66
82
  }
83
+ getUniqueName() {
84
+ throw new Error("Method not implemented.");
85
+ }
67
86
  getSettings() {
68
87
  return this.settings;
69
88
  }
@@ -73,6 +92,20 @@ class IncyclistDevice extends stream_1.EventEmitter {
73
92
  onData(callback) {
74
93
  this.onDataFn = callback;
75
94
  }
95
+ canSendUpdate() {
96
+ const updateFrequency = this.getMaxUpdateFrequency();
97
+ if (updateFrequency === -1 || updateFrequency === undefined)
98
+ return true;
99
+ return (!this.lastUpdate || (Date.now() - this.lastUpdate) > updateFrequency);
100
+ }
101
+ emitData(data) {
102
+ if (!this.canSendUpdate())
103
+ return;
104
+ if (this.onDataFn)
105
+ this.onDataFn(data);
106
+ this.emit('data', this.getSettings(), data);
107
+ this.lastUpdate = Date.now();
108
+ }
76
109
  isStopped() {
77
110
  return this.stopped;
78
111
  }
@@ -82,6 +115,9 @@ class IncyclistDevice extends stream_1.EventEmitter {
82
115
  isPaused() {
83
116
  return this.paused;
84
117
  }
118
+ hasDataListeners() {
119
+ return this.onDataFn || this.listenerCount('data') > 0;
120
+ }
85
121
  }
86
122
  exports.default = IncyclistDevice;
87
123
  class ControllableDevice extends IncyclistDevice {
@@ -90,13 +126,16 @@ class ControllableDevice extends IncyclistDevice {
90
126
  this.cyclingMode = this.getDefaultCyclingMode();
91
127
  this.user = {};
92
128
  }
129
+ isControllable() {
130
+ return true;
131
+ }
93
132
  setUser(user) {
94
133
  this.user = user;
95
134
  if (!user.weight)
96
135
  this.user.weight = exports.DEFAULT_USER_WEIGHT;
97
136
  }
98
137
  setBikeProps(props) {
99
- const { user, userWeight, bikeWeight } = props || {};
138
+ const { user, userWeight } = props || {};
100
139
  if (user)
101
140
  this.setUser(user);
102
141
  if (userWeight)
@@ -1,31 +1,33 @@
1
1
  import { DeviceProperties } from "../types/device";
2
- import { BleComms } from "./ble-comms";
3
- import BleAdapter from "./adapter";
4
- import { BleDeviceSettings } from "./types";
2
+ import BleAdapter from "./base/adapter";
3
+ import { BleDeviceSettings, BleProtocol } from "./types";
4
+ import { BleComms } from "./base/comms";
5
5
  export interface BleAdapterInfo {
6
- protocol: string;
7
- profile: string;
6
+ protocol: BleProtocol;
8
7
  Adapter: typeof BleAdapter;
9
8
  Comm: typeof BleComms;
10
9
  }
11
- export declare function mapLegacyProfile(profile: any): {
12
- profile: any;
13
- protocol: string;
14
- };
15
10
  export default class BleAdapterFactory {
16
11
  static _instance: BleAdapterFactory;
17
- adapters: BleAdapterInfo[];
12
+ implementations: BleAdapterInfo[];
13
+ instances: BleAdapter[];
18
14
  static getInstance(): BleAdapterFactory;
19
15
  constructor();
20
- getAdapter(protocol: string): BleAdapterInfo;
21
- getAllAdapters(): BleAdapterInfo[];
16
+ getAdapterInfo(protocol: BleProtocol): BleAdapterInfo;
17
+ getAll(): BleAdapterInfo[];
22
18
  createInstance(settings: BleDeviceSettings, props?: DeviceProperties): BleAdapter;
23
- register(protocol: string, profile: string, Adapter: typeof BleAdapter, Comm: typeof BleComms): void;
24
- getAllSupportedDeviceTypes(): (typeof BleComms)[];
19
+ removeInstance(query: {
20
+ settings?: BleDeviceSettings;
21
+ adapter?: BleAdapter;
22
+ }): void;
23
+ find(settings?: BleDeviceSettings): BleAdapter;
24
+ register(protocol: BleProtocol, Adapter: typeof BleAdapter, Comm: typeof BleComms): void;
25
+ getAllInstances(): BleAdapter[];
26
+ getAllSupportedComms(): (typeof BleComms)[];
27
+ getAllSupportedAdapters(): (typeof BleAdapter)[];
25
28
  getAllSupportedServices(): string[];
26
29
  getDeviceClasses(peripheral: any, props?: {
27
- deviceTypes?: (typeof BleComms)[];
28
- profile?: string;
30
+ protocol?: BleProtocol;
29
31
  services?: string[];
30
32
  }): (typeof BleComms)[];
31
33
  }