incyclist-devices 1.4.48 → 1.4.51

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.
@@ -12,6 +12,7 @@ import BleInterface from './ble/ble-interface';
12
12
  import BleHrmDevice from './ble/hrm';
13
13
  import BleCyclingPowerDevice from './ble/pwr';
14
14
  import BleFitnessMachineDevice from './ble/fm';
15
+ import WahooAdvancedFitnessMachineDevice from './ble/wahoo-kickr';
15
16
  declare const Protocols: {
16
17
  SimulatorProtocol: typeof SimulatorProtocol;
17
18
  DaumClassicProtocol: typeof DaumClassicProtocol;
@@ -19,4 +20,4 @@ declare const Protocols: {
19
20
  KettlerRacerProtocol: typeof KettlerRacerProtocol;
20
21
  BleProtocol: typeof BleProtocol;
21
22
  };
22
- export { DeviceProtocolBase, DeviceProtocol, DeviceRegistry, INTERFACE, DeviceAdapter as Device, Protocols, AntScanner, BleProtocol, CyclingModeProperyType, BleInterface, BleHrmDevice, BleCyclingPowerDevice, BleFitnessMachineDevice };
23
+ export { DeviceProtocolBase, DeviceProtocol, DeviceRegistry, INTERFACE, DeviceAdapter as Device, Protocols, AntScanner, BleProtocol, CyclingModeProperyType, BleInterface, BleHrmDevice, BleCyclingPowerDevice, BleFitnessMachineDevice, WahooAdvancedFitnessMachineDevice };
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.BleFitnessMachineDevice = exports.BleCyclingPowerDevice = exports.BleHrmDevice = exports.BleInterface = exports.CyclingModeProperyType = exports.BleProtocol = exports.AntScanner = exports.Protocols = exports.Device = exports.INTERFACE = exports.DeviceRegistry = exports.DeviceProtocolBase = void 0;
29
+ exports.WahooAdvancedFitnessMachineDevice = exports.BleFitnessMachineDevice = exports.BleCyclingPowerDevice = exports.BleHrmDevice = exports.BleInterface = exports.CyclingModeProperyType = exports.BleProtocol = exports.AntScanner = exports.Protocols = exports.Device = exports.INTERFACE = exports.DeviceRegistry = exports.DeviceProtocolBase = void 0;
30
30
  const DeviceRegistry_1 = __importDefault(require("./DeviceRegistry"));
31
31
  exports.DeviceRegistry = DeviceRegistry_1.default;
32
32
  const Device_1 = __importDefault(require("./Device"));
@@ -52,6 +52,8 @@ const pwr_1 = __importDefault(require("./ble/pwr"));
52
52
  exports.BleCyclingPowerDevice = pwr_1.default;
53
53
  const fm_1 = __importDefault(require("./ble/fm"));
54
54
  exports.BleFitnessMachineDevice = fm_1.default;
55
+ const wahoo_kickr_1 = __importDefault(require("./ble/wahoo-kickr"));
56
+ exports.WahooAdvancedFitnessMachineDevice = wahoo_kickr_1.default;
55
57
  const Protocols = {
56
58
  SimulatorProtocol: Simulator_1.default,
57
59
  DaumClassicProtocol: DaumClassicProtocol_1.default,
@@ -6,6 +6,13 @@ interface BleDeviceConstructProps extends BleDeviceProps {
6
6
  log?: boolean;
7
7
  logger?: EventLogger;
8
8
  }
9
+ declare type CommandQueueItem = {
10
+ uuid: string;
11
+ data: Buffer;
12
+ resolve: any;
13
+ reject: any;
14
+ timeout: any;
15
+ };
9
16
  export declare abstract class BleDevice extends BleDeviceClass {
10
17
  id: string;
11
18
  address: string;
@@ -19,8 +26,10 @@ export declare abstract class BleDevice extends BleDeviceClass {
19
26
  deviceInfo: BleDeviceInfo;
20
27
  isInitialized: boolean;
21
28
  subscribedCharacteristics: string[];
29
+ writeQueue: CommandQueueItem[];
22
30
  constructor(props?: BleDeviceConstructProps);
23
31
  logEvent(event: any): void;
32
+ setLogger(logger: EventLogger): void;
24
33
  setInterface(ble: BleInterfaceClass): void;
25
34
  cleanupListeners(): void;
26
35
  onDisconnect(): void;
@@ -32,8 +41,8 @@ export declare abstract class BleDevice extends BleDeviceClass {
32
41
  connect(props?: ConnectProps): Promise<boolean>;
33
42
  disconnect(): Promise<boolean>;
34
43
  abstract getProfile(): string;
35
- abstract onData(characteristic: string, data: Buffer): void;
36
- write(characteristicUuid: string, data: Buffer, withoutResponse?: boolean): Promise<boolean>;
44
+ onData(characteristic: string, data: Buffer): void;
45
+ write(characteristicUuid: string, data: Buffer, withoutResponse?: boolean): Promise<ArrayBuffer>;
37
46
  read(characteristicUuid: string): Promise<Uint8Array>;
38
47
  getDeviceInfo(): Promise<BleDeviceInfo>;
39
48
  }
@@ -26,6 +26,7 @@ class BleDevice extends ble_1.BleDeviceClass {
26
26
  this.characteristics = [];
27
27
  this.subscribedCharacteristics = [];
28
28
  this.isInitialized = false;
29
+ this.writeQueue = [];
29
30
  if (props.peripheral) {
30
31
  const { id, address, advertisement, state } = props.peripheral;
31
32
  this.peripheral = props.peripheral;
@@ -38,7 +39,7 @@ class BleDevice extends ble_1.BleDeviceClass {
38
39
  if (props.logger) {
39
40
  this.logger = props.logger;
40
41
  }
41
- else if (props.log) {
42
+ else if (props.log !== false) {
42
43
  this.logger = new gd_eventlog_1.EventLogger('BleDevice');
43
44
  }
44
45
  }
@@ -50,6 +51,9 @@ class BleDevice extends ble_1.BleDeviceClass {
50
51
  console.log('~~~BLE:', event);
51
52
  }
52
53
  }
54
+ setLogger(logger) {
55
+ this.logger = logger;
56
+ }
53
57
  setInterface(ble) {
54
58
  this.ble = ble;
55
59
  }
@@ -103,6 +107,7 @@ class BleDevice extends ble_1.BleDeviceClass {
103
107
  return Promise.resolve(true);
104
108
  return this.getDeviceInfo().then(() => {
105
109
  this.emit('deviceInfo', this.deviceInfo);
110
+ this.logEvent(Object.assign({ message: 'ftms device init done' }, this.deviceInfo));
106
111
  this.isInitialized = true;
107
112
  return true;
108
113
  });
@@ -235,9 +240,20 @@ class BleDevice extends ble_1.BleDeviceClass {
235
240
  }
236
241
  });
237
242
  }
243
+ onData(characteristic, data) {
244
+ if (this.writeQueue.length > 0) {
245
+ const writeIdx = this.writeQueue.findIndex(i => i.uuid === characteristic.toLocaleLowerCase());
246
+ if (writeIdx !== -1) {
247
+ const writeItem = this.writeQueue[writeIdx];
248
+ this.writeQueue.splice(writeIdx, 1);
249
+ if (writeItem.resolve)
250
+ writeItem.resolve(data);
251
+ }
252
+ }
253
+ }
238
254
  write(characteristicUuid, data, withoutResponse = false) {
239
255
  return __awaiter(this, void 0, void 0, function* () {
240
- if (this.subscribedCharacteristics.find(c => c === characteristicUuid) === undefined) {
256
+ if (!withoutResponse && this.subscribedCharacteristics.find(c => c === characteristicUuid) === undefined) {
241
257
  const connector = this.ble.getConnector(this.peripheral);
242
258
  connector.on(characteristicUuid, (uuid, data) => {
243
259
  this.onData(uuid, data);
@@ -251,11 +267,18 @@ class BleDevice extends ble_1.BleDeviceClass {
251
267
  reject(new Error('Characteristic not found'));
252
268
  return;
253
269
  }
270
+ if (withoutResponse) {
271
+ characteristic.write(data, withoutResponse);
272
+ resolve(new ArrayBuffer(0));
273
+ return;
274
+ }
275
+ const writeId = this.writeQueue.length;
276
+ this.writeQueue.push({ uuid: characteristicUuid.toLocaleLowerCase(), data, resolve, reject, timeout: Date.now() + 1000 });
254
277
  characteristic.write(data, withoutResponse, (err) => {
255
- if (err)
278
+ if (err) {
279
+ this.writeQueue.splice(writeId, 1);
256
280
  reject(err);
257
- else
258
- resolve(true);
281
+ }
259
282
  });
260
283
  });
261
284
  });
@@ -1,18 +1,11 @@
1
1
  import CyclingMode, { CyclingModeProperty, IncyclistBikeData, UpdateRequest } from "../CyclingMode";
2
2
  import PowerBasedCyclingModeBase from "../modes/power-base";
3
3
  import { FmAdapter } from "./fm";
4
- export declare type ERGEvent = {
5
- rpmUpdated?: boolean;
6
- gearUpdated?: boolean;
7
- starting?: boolean;
8
- tsStart?: number;
9
- };
10
- export default class ERGCyclingMode extends PowerBasedCyclingModeBase implements CyclingMode {
4
+ export default class BleERGCyclingMode extends PowerBasedCyclingModeBase implements CyclingMode {
11
5
  prevRequest: UpdateRequest;
12
6
  hasBikeUpdate: boolean;
13
7
  chain: number[];
14
8
  cassette: number[];
15
- event: ERGEvent;
16
9
  constructor(adapter: FmAdapter, props?: any);
17
10
  getName(): string;
18
11
  getDescription(): string;
@@ -13,11 +13,11 @@ const config = {
13
13
  { key: 'startPower', name: 'Starting Power', description: 'Initial power in Watts at start of training', type: CyclingMode_1.CyclingModeProperyType.Integer, default: 50, min: 25, max: 800 },
14
14
  ]
15
15
  };
16
- class ERGCyclingMode extends power_base_1.default {
16
+ const MIN_SPEED = 10;
17
+ class BleERGCyclingMode extends power_base_1.default {
17
18
  constructor(adapter, props) {
18
19
  super(adapter, props);
19
20
  this.hasBikeUpdate = false;
20
- this.event = {};
21
21
  this.initLogger('ERGMode');
22
22
  }
23
23
  getName() {
@@ -34,7 +34,7 @@ class ERGCyclingMode extends power_base_1.default {
34
34
  }
35
35
  getBikeInitRequest() {
36
36
  const startPower = this.getSetting('startPower');
37
- return { targetPower: startPower };
37
+ return { slope: 0, targetPower: startPower };
38
38
  }
39
39
  sendBikeUpdate(request) {
40
40
  const getData = () => {
@@ -43,25 +43,18 @@ class ERGCyclingMode extends power_base_1.default {
43
43
  const { pedalRpm, slope, power, speed } = this.data;
44
44
  return { pedalRpm, slope, power, speed };
45
45
  };
46
- this.logger.logEvent({ message: "processing update request", request, prev: this.prevRequest, data: getData(), event: this.event });
46
+ this.logger.logEvent({ message: "processing update request", request, prev: this.prevRequest, data: getData() });
47
47
  let newRequest = {};
48
48
  try {
49
49
  if (!request || request.reset || Object.keys(request).length === 0) {
50
50
  this.prevRequest = {};
51
- return request || {};
51
+ return request.reset ? { reset: true } : {};
52
52
  }
53
53
  const prevData = this.data || {};
54
54
  if (request.targetPower !== undefined) {
55
55
  delete request.slope;
56
56
  delete request.refresh;
57
57
  }
58
- if (this.event.starting && request.targetPower === undefined) {
59
- newRequest.targetPower = this.getSetting('startPower');
60
- if (this.event.tsStart && Date.now() - this.event.tsStart > 5000) {
61
- delete this.event.starting;
62
- delete this.event.tsStart;
63
- }
64
- }
65
58
  if (request.refresh) {
66
59
  delete request.refresh;
67
60
  newRequest.targetPower = this.prevRequest.targetPower;
@@ -70,14 +63,12 @@ class ERGCyclingMode extends power_base_1.default {
70
63
  if (!this.data)
71
64
  this.data = {};
72
65
  this.data.slope = request.slope;
66
+ delete request.slope;
73
67
  }
74
68
  if (request.maxPower !== undefined && request.minPower !== undefined && request.maxPower === request.minPower) {
75
69
  request.targetPower = request.maxPower;
76
- }
77
- if (request.targetPower !== undefined) {
78
70
  newRequest.targetPower = request.targetPower;
79
71
  }
80
- delete request.slope;
81
72
  if (request.maxPower !== undefined) {
82
73
  if (newRequest.targetPower !== undefined && newRequest.targetPower > request.maxPower) {
83
74
  newRequest.targetPower = request.maxPower;
@@ -89,9 +80,8 @@ class ERGCyclingMode extends power_base_1.default {
89
80
  newRequest.targetPower = request.minPower;
90
81
  }
91
82
  newRequest.minPower = request.minPower;
92
- }
93
- if (newRequest.targetPower !== undefined && prevData.power !== undefined && newRequest.targetPower === prevData.power) {
94
- delete newRequest.targetPower;
83
+ if (prevData.power && prevData.power < request.minPower)
84
+ newRequest.targetPower = request.minPower;
95
85
  }
96
86
  this.prevRequest = JSON.parse(JSON.stringify(request));
97
87
  }
@@ -106,36 +96,33 @@ class ERGCyclingMode extends power_base_1.default {
106
96
  const prevRequest = this.prevRequest || {};
107
97
  const data = this.data || {};
108
98
  const bikeType = this.getSetting('bikeType').toLowerCase();
109
- delete this.event.rpmUpdated;
110
- if (prevData === {} || prevData.speed === undefined || prevData.speed === 0) {
111
- this.event.starting = true;
112
- this.event.tsStart = Date.now();
113
- }
114
99
  try {
115
- const rpm = bikeData.pedalRpm || 0;
116
100
  let power = bikeData.power || 0;
117
101
  const slope = (prevData.slope !== undefined ? prevData.slope : prevRequest.slope || 0);
118
102
  const distanceInternal = prevData.distanceInternal || 0;
119
- if (!bikeData.pedalRpm || bikeData.isPedalling === false) {
103
+ if (bikeData.pedalRpm === 0 || bikeData.isPedalling === false) {
120
104
  power = 0;
121
105
  }
122
106
  const m = this.getWeight();
123
107
  const t = this.getTimeSinceLastUpdate();
124
108
  const { speed, distance } = this.calculateSpeedAndDistance(power, slope, m, t, { bikeType });
125
- data.speed = parseFloat(speed.toFixed(1));
109
+ if (power === 0 && speed < MIN_SPEED) {
110
+ data.speed = Math.round(prevData.speed - 1) < 0 ? 0 : Math.round(prevData.speed - 1);
111
+ data.distanceInternal = Math.round(distanceInternal + data.speed / 3.6 * t);
112
+ }
113
+ else {
114
+ data.speed = (power === 0 && speed < MIN_SPEED) ? 0 : speed;
115
+ data.distanceInternal = (power === 0 && speed < MIN_SPEED) ? Math.round(distanceInternal) : Math.round(distanceInternal + distance);
116
+ }
126
117
  data.power = Math.round(power);
127
- data.distanceInternal = Math.round(distanceInternal + distance);
128
118
  data.slope = slope;
129
- data.pedalRpm = rpm;
130
- if (data.time !== undefined && !(this.event.starting && !bikeData.pedalRpm))
119
+ data.pedalRpm = bikeData.pedalRpm || 0;
120
+ if (data.time !== undefined && data.speed > 0)
131
121
  data.time += t;
132
122
  else
133
123
  data.time = 0;
134
124
  data.heartrate = bikeData.heartrate;
135
125
  data.isPedalling = bikeData.isPedalling;
136
- if (rpm && rpm !== prevData.pedalRpm) {
137
- this.event.rpmUpdated = true;
138
- }
139
126
  }
140
127
  catch (err) {
141
128
  this.logger.logEvent({ message: 'error', fn: 'updateData()', error: err.message || err });
@@ -145,4 +132,4 @@ class ERGCyclingMode extends power_base_1.default {
145
132
  return data;
146
133
  }
147
134
  }
148
- exports.default = ERGCyclingMode;
135
+ exports.default = BleERGCyclingMode;
@@ -1,18 +1,9 @@
1
1
  import CyclingMode, { CyclingModeProperty, IncyclistBikeData, UpdateRequest } from "../CyclingMode";
2
2
  import PowerBasedCyclingModeBase from "../modes/power-base";
3
3
  import { FmAdapter } from "./fm";
4
- export declare type ERGEvent = {
5
- rpmUpdated?: boolean;
6
- gearUpdated?: boolean;
7
- starting?: boolean;
8
- tsStart?: number;
9
- };
10
- export default class ERGCyclingMode extends PowerBasedCyclingModeBase implements CyclingMode {
4
+ export default class FtmsCyclingMode extends PowerBasedCyclingModeBase implements CyclingMode {
11
5
  prevRequest: UpdateRequest;
12
6
  hasBikeUpdate: boolean;
13
- chain: number[];
14
- cassette: number[];
15
- event: ERGEvent;
16
7
  constructor(adapter: FmAdapter, props?: any);
17
8
  getName(): string;
18
9
  getDescription(): string;
@@ -9,16 +9,15 @@ const config = {
9
9
  name: "Smart Trainer",
10
10
  description: "Calculates speed based on power and slope. Slope is set to the device",
11
11
  properties: [
12
- { key: 'bikeType', name: 'Bike Type', description: '', type: CyclingMode_1.CyclingModeProperyType.SingleSelect, options: ['Race', 'Mountain', 'Triathlon'], default: 'Race' },
13
- { key: 'startPower', name: 'Starting Power', description: 'Initial power in Watts at start of training', type: CyclingMode_1.CyclingModeProperyType.Integer, default: 50, min: 25, max: 800 },
12
+ { key: 'bikeType', name: 'Bike Type', description: '', type: CyclingMode_1.CyclingModeProperyType.SingleSelect, options: ['Race', 'Mountain', 'Triathlon'], default: 'Race' }
14
13
  ]
15
14
  };
16
- class ERGCyclingMode extends power_base_1.default {
15
+ const MIN_SPEED = 10;
16
+ class FtmsCyclingMode extends power_base_1.default {
17
17
  constructor(adapter, props) {
18
18
  super(adapter, props);
19
19
  this.hasBikeUpdate = false;
20
- this.event = {};
21
- this.initLogger('ERGMode');
20
+ this.initLogger('FtmsMode');
22
21
  }
23
22
  getName() {
24
23
  return config.name;
@@ -33,71 +32,32 @@ class ERGCyclingMode extends power_base_1.default {
33
32
  return config.properties.find(p => p.name === name);
34
33
  }
35
34
  getBikeInitRequest() {
36
- const startPower = this.getSetting('startPower');
37
- return { targetPower: startPower };
35
+ return { slope: 0 };
38
36
  }
39
37
  sendBikeUpdate(request) {
40
38
  const getData = () => {
41
39
  if (!this.data)
42
40
  return {};
43
- const { pedalRpm, slope, power, speed } = this.data;
44
- return { pedalRpm, slope, power, speed };
41
+ const { gear, pedalRpm, slope, power, speed } = this.data;
42
+ return { gear, pedalRpm, slope, power, speed };
45
43
  };
46
- this.logger.logEvent({ message: "processing update request", request, prev: this.prevRequest, data: getData(), event: this.event });
44
+ const event = {};
45
+ if (this.data === undefined)
46
+ event.noData = true;
47
+ if (request.slope !== undefined && (event.noData || Math.abs(request.slope - this.data.slope) >= 0.1))
48
+ event.slopeUpdate = true;
49
+ if (this.prevRequest === undefined)
50
+ event.initialCall = true;
51
+ this.logger.logEvent({ message: "processing update request", request, prev: this.prevRequest, data: getData(), event });
47
52
  let newRequest = {};
48
- try {
49
- if (!request || request.reset || Object.keys(request).length === 0) {
50
- this.prevRequest = {};
51
- return request || {};
52
- }
53
- const prevData = this.data || {};
54
- if (request.targetPower !== undefined) {
55
- delete request.slope;
56
- delete request.refresh;
57
- }
58
- if (this.event.starting && request.targetPower === undefined) {
59
- newRequest.targetPower = this.getSetting('startPower');
60
- if (this.event.tsStart && Date.now() - this.event.tsStart > 5000) {
61
- delete this.event.starting;
62
- delete this.event.tsStart;
63
- }
64
- }
65
- if (request.refresh) {
66
- delete request.refresh;
67
- newRequest.targetPower = this.prevRequest.targetPower;
68
- }
69
- if (request.slope !== undefined) {
70
- if (!this.data)
71
- this.data = {};
72
- this.data.slope = request.slope;
73
- }
74
- if (request.maxPower !== undefined && request.minPower !== undefined && request.maxPower === request.minPower) {
75
- request.targetPower = request.maxPower;
76
- }
77
- if (request.targetPower !== undefined) {
78
- newRequest.targetPower = request.targetPower;
79
- }
80
- delete request.slope;
81
- if (request.maxPower !== undefined) {
82
- if (newRequest.targetPower !== undefined && newRequest.targetPower > request.maxPower) {
83
- newRequest.targetPower = request.maxPower;
84
- }
85
- newRequest.maxPower = request.maxPower;
86
- }
87
- if (request.minPower !== undefined) {
88
- if (newRequest.targetPower !== undefined && newRequest.targetPower < request.minPower) {
89
- newRequest.targetPower = request.minPower;
90
- }
91
- newRequest.minPower = request.minPower;
92
- }
93
- if (newRequest.targetPower !== undefined && prevData.power !== undefined && newRequest.targetPower === prevData.power) {
94
- delete newRequest.targetPower;
95
- }
96
- this.prevRequest = JSON.parse(JSON.stringify(request));
53
+ if (request.slope === undefined && request.refresh && this.prevRequest) {
54
+ return this.prevRequest;
97
55
  }
98
- catch (err) {
99
- this.logger.logEvent({ message: "error", fn: 'sendBikeUpdate()', error: err.message || err, stack: err.stack });
56
+ if (request.slope !== undefined) {
57
+ newRequest.slope = parseFloat(request.slope.toFixed(1));
58
+ this.data.slope = newRequest.slope;
100
59
  }
60
+ this.prevRequest = JSON.parse(JSON.stringify(newRequest));
101
61
  return newRequest;
102
62
  }
103
63
  updateData(bikeData) {
@@ -106,36 +66,33 @@ class ERGCyclingMode extends power_base_1.default {
106
66
  const prevRequest = this.prevRequest || {};
107
67
  const data = this.data || {};
108
68
  const bikeType = this.getSetting('bikeType').toLowerCase();
109
- delete this.event.rpmUpdated;
110
- if (prevData === {} || prevData.speed === undefined || prevData.speed === 0) {
111
- this.event.starting = true;
112
- this.event.tsStart = Date.now();
113
- }
114
69
  try {
115
- const rpm = bikeData.pedalRpm || 0;
116
70
  let power = bikeData.power || 0;
117
71
  const slope = (prevData.slope !== undefined ? prevData.slope : prevRequest.slope || 0);
118
72
  const distanceInternal = prevData.distanceInternal || 0;
119
- if (!bikeData.pedalRpm || bikeData.isPedalling === false) {
73
+ if (bikeData.pedalRpm === 0 || bikeData.isPedalling === false) {
120
74
  power = 0;
121
75
  }
122
76
  const m = this.getWeight();
123
77
  const t = this.getTimeSinceLastUpdate();
124
78
  const { speed, distance } = this.calculateSpeedAndDistance(power, slope, m, t, { bikeType });
125
- data.speed = parseFloat(speed.toFixed(1));
79
+ if (power === 0 && speed < MIN_SPEED) {
80
+ data.speed = Math.round(prevData.speed - 1) < 0 ? 0 : Math.round(prevData.speed - 1);
81
+ data.distanceInternal = Math.round(distanceInternal + data.speed / 3.6 * t);
82
+ }
83
+ else {
84
+ data.speed = (power === 0 && speed < MIN_SPEED) ? 0 : speed;
85
+ data.distanceInternal = (power === 0 && speed < MIN_SPEED) ? Math.round(distanceInternal) : Math.round(distanceInternal + distance);
86
+ }
126
87
  data.power = Math.round(power);
127
- data.distanceInternal = Math.round(distanceInternal + distance);
128
88
  data.slope = slope;
129
- data.pedalRpm = rpm;
130
- if (data.time !== undefined && !(this.event.starting && !bikeData.pedalRpm))
89
+ data.pedalRpm = bikeData.pedalRpm || 0;
90
+ if (data.time !== undefined)
131
91
  data.time += t;
132
92
  else
133
93
  data.time = 0;
134
94
  data.heartrate = bikeData.heartrate;
135
95
  data.isPedalling = bikeData.isPedalling;
136
- if (rpm && rpm !== prevData.pedalRpm) {
137
- this.event.rpmUpdated = true;
138
- }
139
96
  }
140
97
  catch (err) {
141
98
  this.logger.logEvent({ message: 'error', fn: 'updateData()', error: err.message || err });
@@ -145,4 +102,4 @@ class ERGCyclingMode extends power_base_1.default {
145
102
  return data;
146
103
  }
147
104
  }
148
- exports.default = ERGCyclingMode;
105
+ exports.default = FtmsCyclingMode;
package/lib/ble/fm.d.ts CHANGED
@@ -31,6 +31,9 @@ declare type IndoorBikeData = {
31
31
  time?: number;
32
32
  remainingTime?: number;
33
33
  raw?: string;
34
+ targetPower?: number;
35
+ targetInclination?: number;
36
+ status?: string;
34
37
  };
35
38
  declare type IndoorBikeFeatures = {
36
39
  fitnessMachine: number;
@@ -43,6 +46,10 @@ export default class BleFitnessMachineDevice extends BleDevice {
43
46
  features: IndoorBikeFeatures;
44
47
  hasControl: boolean;
45
48
  isCPSubscribed: boolean;
49
+ crr: number;
50
+ cw: number;
51
+ windSpeed: number;
52
+ wheelSize: number;
46
53
  constructor(props?: any);
47
54
  init(): Promise<boolean>;
48
55
  onDisconnect(): void;
@@ -52,11 +59,25 @@ export default class BleFitnessMachineDevice extends BleDevice {
52
59
  isPower(): boolean;
53
60
  isHrm(): boolean;
54
61
  parseHrm(_data: Uint8Array): IndoorBikeData;
62
+ setCrr(crr: number): void;
63
+ getCrr(): number;
64
+ setCw(cw: number): void;
65
+ getCw(): number;
66
+ setWindSpeed(windSpeed: number): void;
67
+ getWindSpeed(): number;
55
68
  parseIndoorBikeData(_data: Uint8Array): IndoorBikeData;
69
+ parseFitnessMachineStatus(_data: Uint8Array): IndoorBikeData;
56
70
  getFitnessMachineFeatures(): Promise<IndoorBikeFeatures>;
57
71
  onData(characteristic: string, data: Buffer): void;
72
+ writeFtmsMessage(requestedOpCode: any, data: any): Promise<number>;
58
73
  requestControl(): Promise<boolean>;
59
- setTargetPower(power: number): Promise<void>;
74
+ setTargetPower(power: number): Promise<boolean>;
75
+ setSlope(slope: any): Promise<boolean>;
76
+ setTargetInclination(inclination: number): Promise<boolean>;
77
+ setIndoorBikeSimulation(windSpeed: number, gradient: number, crr: number, cw: number): Promise<boolean>;
78
+ startRequest(): Promise<boolean>;
79
+ stopRequest(): Promise<boolean>;
80
+ PauseRequest(): Promise<boolean>;
60
81
  reset(): void;
61
82
  }
62
83
  export declare class FmAdapter extends DeviceAdapter {
@@ -66,7 +87,7 @@ export declare class FmAdapter extends DeviceAdapter {
66
87
  protocol: DeviceProtocol;
67
88
  paused: boolean;
68
89
  logger: EventLogger;
69
- mode: CyclingMode;
90
+ cyclingMode: CyclingMode;
70
91
  distanceInternal: number;
71
92
  prevDataTS: number;
72
93
  constructor(device: BleDeviceClass, protocol: BleProtocol);
@@ -77,6 +98,8 @@ export declare class FmAdapter extends DeviceAdapter {
77
98
  getProfile(): string;
78
99
  getName(): string;
79
100
  getDisplayName(): string;
101
+ getSupportedCyclingModes(): Array<any>;
102
+ setCyclingMode(mode: string | CyclingMode, settings?: any): void;
80
103
  getCyclingMode(): CyclingMode;
81
104
  getDefaultCyclingMode(): CyclingMode;
82
105
  getPort(): string;