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.
- package/README.MD +238 -0
- package/lib/adapters.d.ts +1 -0
- package/lib/adapters.js +19 -0
- package/lib/antv2/adapter-factory.d.ts +8 -7
- package/lib/antv2/adapter-factory.js +4 -2
- package/lib/antv2/adapter.d.ts +3 -2
- package/lib/antv2/adapter.js +15 -4
- package/lib/antv2/ant-interface.d.ts +6 -2
- package/lib/antv2/ant-interface.js +27 -21
- package/lib/antv2/binding.d.ts +1 -1
- package/lib/antv2/binding.js +1 -1
- package/lib/antv2/fe/adapter.d.ts +12 -9
- package/lib/antv2/fe/adapter.js +67 -27
- package/lib/antv2/hr/adapter.d.ts +6 -5
- package/lib/antv2/hr/adapter.js +19 -16
- package/lib/antv2/index.d.ts +2 -2
- package/lib/antv2/pwr/adapter.d.ts +6 -4
- package/lib/antv2/pwr/adapter.js +24 -16
- package/lib/antv2/sensor-factory.d.ts +2 -2
- package/lib/antv2/types.d.ts +5 -2
- package/lib/antv2/types.js +3 -0
- package/lib/antv2/utils.d.ts +3 -0
- package/lib/antv2/utils.js +12 -1
- package/lib/base/adpater.d.ts +14 -2
- package/lib/base/adpater.js +43 -4
- package/lib/ble/adapter-factory.d.ts +18 -16
- package/lib/ble/adapter-factory.js +54 -45
- package/lib/ble/base/adapter.d.ts +53 -0
- package/lib/ble/{adapter.js → base/adapter.js} +111 -9
- package/lib/ble/base/comms-utils.d.ts +7 -0
- package/lib/ble/base/comms-utils.js +91 -0
- package/lib/ble/{ble-comms.d.ts → base/comms.d.ts} +27 -17
- package/lib/ble/{ble-comms.js → base/comms.js} +179 -53
- package/lib/ble/bindings/index.d.ts +2 -0
- package/lib/ble/bindings/index.js +8 -0
- package/lib/ble/bindings/linux.d.ts +15 -0
- package/lib/ble/bindings/linux.js +39 -0
- package/lib/ble/bindings/mock.d.ts +9 -0
- package/lib/ble/bindings/mock.js +108 -0
- package/lib/ble/bindings/types.d.ts +57 -0
- package/lib/ble/bindings/types.js +96 -0
- package/lib/ble/ble-interface.d.ts +34 -46
- package/lib/ble/ble-interface.js +242 -345
- package/lib/ble/ble-peripheral.d.ts +4 -2
- package/lib/ble/ble-peripheral.js +39 -8
- package/lib/ble/consts.d.ts +1 -0
- package/lib/ble/consts.js +2 -1
- package/lib/ble/cp/adapter.d.ts +1 -2
- package/lib/ble/cp/adapter.js +2 -15
- package/lib/ble/cp/comm.d.ts +8 -5
- package/lib/ble/cp/comm.js +12 -27
- package/lib/ble/elite/adapter.d.ts +1 -2
- package/lib/ble/elite/adapter.js +12 -19
- package/lib/ble/elite/comms.d.ts +8 -4
- package/lib/ble/elite/comms.js +12 -25
- package/lib/ble/fm/adapter.d.ts +3 -2
- package/lib/ble/fm/adapter.js +129 -70
- package/lib/ble/fm/comms.d.ts +8 -8
- package/lib/ble/fm/comms.js +33 -55
- package/lib/ble/fm/types.d.ts +5 -0
- package/lib/ble/hr/adapter.d.ts +1 -4
- package/lib/ble/hr/adapter.js +1 -18
- package/lib/ble/hr/comm.d.ts +6 -2
- package/lib/ble/hr/comm.js +6 -2
- package/lib/ble/hr/mock.d.ts +7 -0
- package/lib/ble/hr/mock.js +47 -0
- package/lib/ble/index.d.ts +2 -1
- package/lib/ble/index.js +5 -5
- package/lib/ble/peripheral-cache.d.ts +43 -0
- package/lib/ble/peripheral-cache.js +107 -0
- package/lib/ble/tacx/adapter.d.ts +1 -1
- package/lib/ble/tacx/adapter.js +20 -14
- package/lib/ble/tacx/comms.d.ts +6 -6
- package/lib/ble/tacx/comms.js +10 -43
- package/lib/ble/types.d.ts +54 -27
- package/lib/ble/types.js +0 -17
- package/lib/ble/utils.d.ts +15 -5
- package/lib/ble/utils.js +25 -66
- package/lib/ble/wahoo/adapter.d.ts +1 -1
- package/lib/ble/wahoo/adapter.js +12 -10
- package/lib/ble/wahoo/comms.d.ts +7 -6
- package/lib/ble/wahoo/comms.js +15 -17
- package/lib/index.d.ts +10 -7
- package/lib/index.js +21 -25
- package/lib/interfaces.d.ts +2 -1
- package/lib/interfaces.js +4 -0
- package/lib/modes/power-base.js +4 -0
- package/lib/serial/adapter.d.ts +5 -0
- package/lib/serial/adapter.js +19 -0
- package/lib/serial/bindings/tcp.d.ts +2 -1
- package/lib/serial/bindings/tcp.js +19 -5
- package/lib/serial/daum/DaumAdapter.d.ts +1 -1
- package/lib/serial/daum/DaumAdapter.js +16 -10
- package/lib/serial/daum/premium/adapter.d.ts +1 -0
- package/lib/serial/daum/premium/adapter.js +9 -2
- package/lib/serial/daum/premium/comms.js +10 -3
- package/lib/serial/daum/premium/mock.js +0 -1
- package/lib/serial/index.d.ts +3 -3
- package/lib/serial/index.js +2 -2
- package/lib/serial/kettler/ergo-racer/adapter.d.ts +1 -4
- package/lib/serial/kettler/ergo-racer/adapter.js +15 -39
- package/lib/serial/serial-interface.d.ts +3 -1
- package/lib/serial/serial-interface.js +43 -17
- package/lib/simulator/Simulator.d.ts +2 -0
- package/lib/simulator/Simulator.js +8 -5
- package/lib/types/adapter.d.ts +10 -3
- package/lib/types/device.d.ts +3 -0
- package/lib/types/interface.d.ts +7 -3
- package/package.json +3 -5
- package/lib/ble/adapter.d.ts +0 -41
- package/lib/ble/ble.d.ts +0 -57
- package/lib/ble/ble.js +0 -48
- package/lib/device.d.ts +0 -0
- package/lib/device.js +0 -0
package/README.MD
CHANGED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# incyclist-devices
|
|
2
|
+
|
|
3
|
+
Library used by the [Incyclist](https://incyclist.com) Indoor Cycling App to communicate with devices (Smart Trainers, Sensors)
|
|
4
|
+
|
|
5
|
+
It currently support the following Interfaces/Devices
|
|
6
|
+
|
|
7
|
+
__ANT__
|
|
8
|
+
- Smart Trainers (ANT+ FE)
|
|
9
|
+
- Power Meters (ANT+PWR)
|
|
10
|
+
- Heartrate Monitors (ANT+HR)
|
|
11
|
+
|
|
12
|
+
__BLE__
|
|
13
|
+
- Smart Trainers (BLE FTMS)
|
|
14
|
+
- Power Meters (BLE CP)
|
|
15
|
+
- Heartrate Monitors (BLE HR)
|
|
16
|
+
- Wahoo Smart Trainers (Wahoo specific service)
|
|
17
|
+
- Tacx FE-C over BLE
|
|
18
|
+
|
|
19
|
+
__Serial__
|
|
20
|
+
- Daum Classic Ergo Bikes
|
|
21
|
+
- Daum Premium Ergo Bikes (also over TCP/IP)
|
|
22
|
+
- Kettler Ergo Racer Ergo Bikes
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
npm install incyclist-devices
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
### Setup Interfaces and Bindings
|
|
34
|
+
|
|
35
|
+
`Interface` classes are used to enable basic communication (transport layer).
|
|
36
|
+
|
|
37
|
+
As this library supports various OS( Linux, Windows, Mac) and Incyclist is based on Electron, which requires to clearly separate between rendering and main process, Bindings need to be provided for each of the Interfaces. The specifications of these bindings are specific to the interface:
|
|
38
|
+
- Ant: specified by the [incyclist-ant-plus](https://github.com/incyclist/ant-plus) library
|
|
39
|
+
- Serial: specified by the [serialport](https://serialport.io/) library
|
|
40
|
+
- BLE: specified by the [noble](https://github.com/noble/noble) library
|
|
41
|
+
|
|
42
|
+
__Ant Example__
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
const {EventLogger,ConsoleAdapter} = require( 'gd-eventlog');
|
|
46
|
+
const {AntDevice} = require('incyclist-ant-plus/lib/bindings');
|
|
47
|
+
|
|
48
|
+
const logger = new EventLogger('AntSample')
|
|
49
|
+
const ant = InterfaceFactory.create('ant',{logger, log:true, binding:AntDevice})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
__Serial Example__
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
const {EventLogger,ConsoleAdapter} = require( 'gd-eventlog');
|
|
56
|
+
const { autoDetect } = require('@serialport/bindings-cpp')
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
const logger = new EventLogger('SerialSample')
|
|
60
|
+
const serial = InterfaceFactory.create('serial',{logger, log:true, binding:autodetect()})
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
__BLE Example__
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
const {EventLogger,ConsoleAdapter} = require( 'gd-eventlog');
|
|
67
|
+
const {WinrtBindings} = require('./bindings')
|
|
68
|
+
const Noble = require('noble/lib/noble');
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
const noble = new Noble(new WinrtBindings())
|
|
72
|
+
const logger = new EventLogger('BLESample')
|
|
73
|
+
const ble = InterfaceFactory.create('ble',{logger, log:true, binding:noble})
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Check availability of interface
|
|
77
|
+
|
|
78
|
+
For some interfaces (ANT and BLE) it cannot be guaranteed that the underlying hardware supports the interface ( e.g. a USB stick might be required). Therefore this library offers a `connect` method, that allows to check if the interface is availabe
|
|
79
|
+
|
|
80
|
+
__Ant Example__
|
|
81
|
+
```
|
|
82
|
+
const connected = await ant.connect() // tries to establish communication and blocks USB stick for usage with other apps
|
|
83
|
+
if (connect) {
|
|
84
|
+
....
|
|
85
|
+
await ant.disconnect() // closes communication and unblocks USB stick
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
...
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Scan for devices
|
|
93
|
+
|
|
94
|
+
Every interface offers a method `scan` that allows to scan for devices. The timeout for the scan can be specified in the properties. If those are not provided, a default will apply.
|
|
95
|
+
|
|
96
|
+
The scan method returns a `Promise<DeviceSettings[]>` containing the settings of all detected devices.
|
|
97
|
+
|
|
98
|
+
In addition to that, all devices that are detected, will be emitted as `device` event during the scan.
|
|
99
|
+
|
|
100
|
+
The method `stopScan`can be used to stop an ongoing scan.
|
|
101
|
+
|
|
102
|
+
__Examples__
|
|
103
|
+
|
|
104
|
+
- Example 1: wait for teh result of the scan
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
_interface.on('device',(deviceSettings:DeviceSettings)=>{console.log('Device found', DeviceSettings)})
|
|
108
|
+
const devices = await _interface_.scan({timeout:20000})
|
|
109
|
+
console.log(devices)
|
|
110
|
+
```
|
|
111
|
+
- Example 2: stop scan as soon as one device was found
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
_interface.on('device',async (deviceSettings:DeviceSettings)=>{
|
|
115
|
+
console.log('Device found', DeviceSettings)
|
|
116
|
+
await _interface.stopScan()
|
|
117
|
+
})
|
|
118
|
+
_interface_.scan({timeout:20000})
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
### Create a device
|
|
124
|
+
|
|
125
|
+
The Devices library provides and `AdapterFactory`, which allows you to create a device adapters, based on the specifications provided in a `DeviceSettings` object.
|
|
126
|
+
|
|
127
|
+
The exact content if this object varies between the interfaces:
|
|
128
|
+
|
|
129
|
+
- __Ant__: interface ('ant'), profile( one of 'HR','PWR', 'FE'), deviceID
|
|
130
|
+
|
|
131
|
+
- __BLE__: interface ('ble'), protocol( one of 'fm','cp,'hr', 'tacx', 'wahoo'), name, id or address
|
|
132
|
+
|
|
133
|
+
- __Serial__: interface('serial' or 'tcpip'), protocol( one of 'Daum Premium', 'Daum Classic', 'Kettler Racer'), name, port, host (only for TCP/IP)
|
|
134
|
+
|
|
135
|
+
These device adapters are used by Incyclist to communicate with the devices. The AdapterFactory will ensure that for a given device only one instance of a device adapter will be provided, to avoid that two classes will concurrently communicate with the same physical device.
|
|
136
|
+
|
|
137
|
+
At the point where a device adapter is created, the constructor will _not_ try to communicate with the device. I.e. the adapter can be created even if no such device is available/connected.
|
|
138
|
+
|
|
139
|
+
__Example__
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
const {AdapterFactory} = require('incyclist-devices')
|
|
143
|
+
|
|
144
|
+
const device = AdapterFactory.create({interface:'ble, protocol:'fm', name:'KICKR BIKE 1234'})
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
### Communicate with a device
|
|
150
|
+
|
|
151
|
+
In order to commuicate with the device, the device firstly has to be started
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
#### __start( props?: DeviceProperties):Promise\<boolean\>__
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
you then should register for events:
|
|
158
|
+
|
|
159
|
+
- __data__ (device:DeviceSettings, data: DeviceData): is emitted whenever a device/sensor has sent data
|
|
160
|
+
- device: describes the device that has sent data
|
|
161
|
+
- data: provides the data that the device/sensor has provided (power, speed, cadence,slope, heartrate, timestamp,... )
|
|
162
|
+
|
|
163
|
+
- __disconnected__ (device:DeviceSettings): is emitted when the library has not recieved any udate for a configurable time or the underlying interface has recognized a connection loss
|
|
164
|
+
- device: describes the device that has sent data
|
|
165
|
+
|
|
166
|
+
- __device-info__- (device:DeviceSettings, info:): signals that additional information about the device was received ( e.g. manufacturer, additional features/capabilities)
|
|
167
|
+
- device: describes the device that has sent data
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
try {
|
|
172
|
+
await device.start({timeout:5000, userWeight:90,bikeWeight:10})
|
|
173
|
+
device.on('data',(deviceInfo,data)=> { console.log('device data', deviceInfo,data) })
|
|
174
|
+
device.on('disconnected',(deviceInfo)=> {
|
|
175
|
+
console.log('device disconnected', deviceInfo)
|
|
176
|
+
// check if reconnect makes sense
|
|
177
|
+
device.disconnect()
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
catch(err) {
|
|
181
|
+
console.log('device could not be started, reason', err.message)
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
#### __setMaxUpdateFrequency(ms:number):void__
|
|
186
|
+
#### __getMaxUpdateFrequency():number__
|
|
187
|
+
|
|
188
|
+
BLE and ANT devices might send data more frequently than you mihgt want to process in your app. Therefore you can control how often you want to receive updates from a device.
|
|
189
|
+
|
|
190
|
+
Default value is 1s
|
|
191
|
+
|
|
192
|
+
A value of -1 indicates that the app wants to receive any data without delays
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
device.setMaxUpdateFrequency(1000) // send update every 1000ms
|
|
196
|
+
const updateFrequency = device.getMaxUpdateFrequency()
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
#### __setPullFrequency(ms:number):void__
|
|
201
|
+
#### __getPullFrequency():number__
|
|
202
|
+
|
|
203
|
+
Serial Devices are typically not automatically sending data, but the app has to actively pull. Therefore the Serial device adapters also offer the capability to control how often the library will pull data from the device
|
|
204
|
+
|
|
205
|
+
Default value is 1s
|
|
206
|
+
|
|
207
|
+
_Warning_: Setting this value to low might overload the serial port and you might not receive any data
|
|
208
|
+
|
|
209
|
+
#### __stop():Promise\<boolean\>__
|
|
210
|
+
|
|
211
|
+
Once the commeunication is not required anymore, you can call stop() to close the connection. This will also automatically unregister the event listeners.
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
#### __pause():Promise\<boolean\>__
|
|
215
|
+
#### __resume():Promise\<boolean\>__
|
|
216
|
+
|
|
217
|
+
In some cases it might sense to not further receive any update from the device, but still keep the communication open. In thise case, pause() and resume() can be called.
|
|
218
|
+
|
|
219
|
+
During a paused state, no event will be emitted
|
|
220
|
+
|
|
221
|
+
#### __sendUpdate(request:UpdateRequest):Promise\<boolean\>__
|
|
222
|
+
|
|
223
|
+
Allows to send data to the device, typically one of the following data will be sent
|
|
224
|
+
|
|
225
|
+
__slope__: (SIM Mode) sets the slope/incline. The smart trainer then will adjust power accordingly
|
|
226
|
+
|
|
227
|
+
__targetPower__: (ERG Mode) sets the power that the smart trainer should
|
|
228
|
+
|
|
229
|
+
__reset__: returns to the default settings at the start of the training
|
|
230
|
+
|
|
231
|
+
__resfresh__: repeats the previous update
|
|
232
|
+
|
|
233
|
+
This method should only be called for SmartTrainers or PowerMeters
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
## Examples
|
|
237
|
+
|
|
238
|
+
Please have a look at the [example code](./samples)
|
package/lib/adapters.d.ts
CHANGED
|
@@ -2,5 +2,6 @@ import { IncyclistDeviceAdapter } from "./types/adapter";
|
|
|
2
2
|
import { DeviceProperties, DeviceSettings } from "./types/device";
|
|
3
3
|
export default class AdapterFactory {
|
|
4
4
|
static adapters: IncyclistDeviceAdapter[];
|
|
5
|
+
static reset(): void;
|
|
5
6
|
static create(settings: DeviceSettings, props?: DeviceProperties): any;
|
|
6
7
|
}
|
package/lib/adapters.js
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const antv2_1 = require("./antv2");
|
|
4
|
+
const ble_1 = require("./ble");
|
|
4
5
|
const serial_1 = require("./serial");
|
|
6
|
+
const Simulator_1 = require("./simulator/Simulator");
|
|
5
7
|
const device_1 = require("./types/device");
|
|
6
8
|
class AdapterFactory {
|
|
9
|
+
static reset() {
|
|
10
|
+
AdapterFactory.adapters = [];
|
|
11
|
+
ble_1.BleAdapterFactory.getInstance().instances = [];
|
|
12
|
+
}
|
|
7
13
|
static create(settings, props) {
|
|
8
14
|
const adapters = AdapterFactory.adapters;
|
|
15
|
+
if (!settings.interface && settings.protocol === 'Simulator') {
|
|
16
|
+
const adapter = new Simulator_1.Simulator(settings);
|
|
17
|
+
if (adapter) {
|
|
18
|
+
adapters.push(adapter);
|
|
19
|
+
}
|
|
20
|
+
return adapter;
|
|
21
|
+
}
|
|
9
22
|
const existing = adapters.find(a => a.isEqual(settings));
|
|
10
23
|
if (existing)
|
|
11
24
|
return existing;
|
|
@@ -19,6 +32,12 @@ class AdapterFactory {
|
|
|
19
32
|
case device_1.INTERFACE.ANT:
|
|
20
33
|
adapter = antv2_1.AntAdapterFactory.getInstance().createInstance(settings, props);
|
|
21
34
|
break;
|
|
35
|
+
case device_1.INTERFACE.BLE:
|
|
36
|
+
adapter = ble_1.BleAdapterFactory.getInstance().createInstance(settings, props);
|
|
37
|
+
break;
|
|
38
|
+
case device_1.INTERFACE.SIMULATOR:
|
|
39
|
+
adapter = new Simulator_1.Simulator(settings);
|
|
40
|
+
break;
|
|
22
41
|
}
|
|
23
42
|
if (adapter) {
|
|
24
43
|
adapters.push(adapter);
|
|
@@ -1,21 +1,22 @@
|
|
|
1
|
+
import { Profile } from "incyclist-ant-plus";
|
|
1
2
|
import AntAdapter from "./adapter";
|
|
2
|
-
import { AntDeviceProperties, AntDeviceSettings } from "./types";
|
|
3
|
+
import { AntDeviceProperties, AntDeviceSettings, LegacyProfile } from "./types";
|
|
3
4
|
export type AntAdapterInfo = {
|
|
4
|
-
antProfile:
|
|
5
|
-
incyclistProfile:
|
|
5
|
+
antProfile: Profile;
|
|
6
|
+
incyclistProfile: LegacyProfile;
|
|
6
7
|
Adapter: typeof AntAdapter;
|
|
7
8
|
};
|
|
8
9
|
export type AdapterQuery = {
|
|
9
|
-
antProfile?:
|
|
10
|
-
incyclistProfile?:
|
|
10
|
+
antProfile?: Profile;
|
|
11
|
+
incyclistProfile?: LegacyProfile;
|
|
11
12
|
};
|
|
12
13
|
export default class AntAdapterFactory {
|
|
13
14
|
static _instance: AntAdapterFactory;
|
|
14
15
|
adapters: AntAdapterInfo[];
|
|
15
16
|
static getInstance(): AntAdapterFactory;
|
|
16
17
|
constructor();
|
|
17
|
-
register(antProfile:
|
|
18
|
+
register(antProfile: Profile, incyclistProfile: LegacyProfile, Adapter: typeof AntAdapter): void;
|
|
18
19
|
getAdapter(query?: AdapterQuery): any;
|
|
19
20
|
createInstance(settings: AntDeviceSettings, props?: AntDeviceProperties): any;
|
|
20
|
-
createFromDetected(profile:
|
|
21
|
+
createFromDetected(profile: Profile, deviceID: number, props?: AntDeviceProperties): any;
|
|
21
22
|
}
|
|
@@ -32,10 +32,12 @@ class AntAdapterFactory {
|
|
|
32
32
|
let info;
|
|
33
33
|
const { profile, protocol } = settings;
|
|
34
34
|
if (protocol) {
|
|
35
|
-
|
|
35
|
+
const incyclistProfile = profile;
|
|
36
|
+
info = this.getAdapter({ incyclistProfile });
|
|
36
37
|
}
|
|
37
38
|
else {
|
|
38
|
-
|
|
39
|
+
const antProfile = profile;
|
|
40
|
+
info = this.getAdapter({ antProfile });
|
|
39
41
|
}
|
|
40
42
|
if (info && info.Adapter)
|
|
41
43
|
return new info.Adapter(settings, props);
|
package/lib/antv2/adapter.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { IChannel, ISensor } from 'incyclist-ant-plus';
|
|
2
|
+
import { IChannel, ISensor, Profile } from 'incyclist-ant-plus';
|
|
3
3
|
import AntInterface from './ant-interface';
|
|
4
4
|
import IncyclistDevice from '../base/adpater';
|
|
5
5
|
import { AntDeviceProperties, AntDeviceSettings } from './types';
|
|
@@ -41,7 +41,7 @@ export default class AntAdapter extends IncyclistDevice {
|
|
|
41
41
|
getID(): string;
|
|
42
42
|
getName(): string;
|
|
43
43
|
getInterface(): string;
|
|
44
|
-
getProfile():
|
|
44
|
+
getProfile(): Profile;
|
|
45
45
|
startDataTimeoutCheck(): void;
|
|
46
46
|
stopDataTimeoutCheck(): void;
|
|
47
47
|
check(): Promise<boolean>;
|
|
@@ -54,6 +54,7 @@ export declare class ControllableAntAdapter extends AntAdapter implements Bike {
|
|
|
54
54
|
cyclingMode: CyclingMode;
|
|
55
55
|
user?: User;
|
|
56
56
|
constructor(settings: AntDeviceSettings, props?: AntDeviceProperties);
|
|
57
|
+
isControllable(): boolean;
|
|
57
58
|
setUser(user: User): void;
|
|
58
59
|
setBikeProps(props: DeviceProperties): void;
|
|
59
60
|
getWeight(): number;
|
package/lib/antv2/adapter.js
CHANGED
|
@@ -38,6 +38,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
38
38
|
exports.ControllableAntAdapter = exports.DEFAULT_UPDATE_FREQUENCY = void 0;
|
|
39
39
|
const ant_interface_1 = __importDefault(require("./ant-interface"));
|
|
40
40
|
const adpater_1 = __importStar(require("../base/adpater"));
|
|
41
|
+
const types_1 = require("./types");
|
|
41
42
|
const utils_1 = require("../utils/utils");
|
|
42
43
|
const capabilities_1 = require("../types/capabilities");
|
|
43
44
|
const adpater_2 = require("../base/adpater");
|
|
@@ -49,6 +50,9 @@ class AntAdapter extends adpater_1.default {
|
|
|
49
50
|
constructor(settings, props) {
|
|
50
51
|
super(settings, props);
|
|
51
52
|
this.startupRetryPause = 1000;
|
|
53
|
+
const antSettings = this.settings;
|
|
54
|
+
if ((0, types_1.isLegacyProfile)(antSettings.profile))
|
|
55
|
+
antSettings.profile = (0, utils_2.mapLegacyProfile)(antSettings.profile);
|
|
52
56
|
if (this.settings.interface !== 'ant')
|
|
53
57
|
throw new Error('Incorrect interface');
|
|
54
58
|
this.sensor = this.createSensor(settings);
|
|
@@ -66,7 +70,7 @@ class AntAdapter extends adpater_1.default {
|
|
|
66
70
|
const as = this.settings;
|
|
67
71
|
if (as.interface !== settings.interface)
|
|
68
72
|
return false;
|
|
69
|
-
if (as.deviceID
|
|
73
|
+
if (as.deviceID !== settings.deviceID || as.profile !== settings.profile)
|
|
70
74
|
return false;
|
|
71
75
|
return true;
|
|
72
76
|
}
|
|
@@ -100,7 +104,7 @@ class AntAdapter extends adpater_1.default {
|
|
|
100
104
|
const { ManId } = this.deviceData;
|
|
101
105
|
this.deviceData = Object.assign({}, deviceData);
|
|
102
106
|
if (!ManId && deviceData.ManId) {
|
|
103
|
-
this.emit('device-info', { manufacturer: (0, utils_2.getBrand)(deviceData.ManId) });
|
|
107
|
+
this.emit('device-info', { device: this.getSettings(), manufacturer: (0, utils_2.getBrand)(deviceData.ManId) });
|
|
104
108
|
}
|
|
105
109
|
}
|
|
106
110
|
waitForData(timeout) {
|
|
@@ -142,7 +146,11 @@ class AntAdapter extends adpater_1.default {
|
|
|
142
146
|
}
|
|
143
147
|
getProfile() {
|
|
144
148
|
const settings = this.settings;
|
|
145
|
-
|
|
149
|
+
if (settings.protocol === undefined)
|
|
150
|
+
return settings.profile;
|
|
151
|
+
else {
|
|
152
|
+
return (0, utils_2.mapLegacyProfile)(settings.profile);
|
|
153
|
+
}
|
|
146
154
|
}
|
|
147
155
|
startDataTimeoutCheck() {
|
|
148
156
|
if (this.ivDataTimeout)
|
|
@@ -245,13 +253,16 @@ class ControllableAntAdapter extends AntAdapter {
|
|
|
245
253
|
this.cyclingMode = this.getDefaultCyclingMode();
|
|
246
254
|
this.user = {};
|
|
247
255
|
}
|
|
256
|
+
isControllable() {
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
248
259
|
setUser(user) {
|
|
249
260
|
this.user = user;
|
|
250
261
|
if (!user.weight)
|
|
251
262
|
this.user.weight = adpater_2.DEFAULT_USER_WEIGHT;
|
|
252
263
|
}
|
|
253
264
|
setBikeProps(props) {
|
|
254
|
-
const { user, userWeight
|
|
265
|
+
const { user, userWeight } = props || {};
|
|
255
266
|
if (user)
|
|
256
267
|
this.setUser(user);
|
|
257
268
|
if (userWeight)
|
|
@@ -9,6 +9,10 @@ import { AntDeviceSettings, AntScanProps } from "./types";
|
|
|
9
9
|
export interface AntInterfaceProps extends InterfaceProps {
|
|
10
10
|
startupTimeout?: number;
|
|
11
11
|
}
|
|
12
|
+
export interface ConnectState {
|
|
13
|
+
connected: boolean;
|
|
14
|
+
connecting: boolean;
|
|
15
|
+
}
|
|
12
16
|
export default class AntInterface extends EventEmitter implements IncyclistInterface {
|
|
13
17
|
static _instance: AntInterface;
|
|
14
18
|
static INTERFACE_NAME: string;
|
|
@@ -17,8 +21,7 @@ export default class AntInterface extends EventEmitter implements IncyclistInter
|
|
|
17
21
|
protected logger: EventLogger;
|
|
18
22
|
protected device: IAntDevice;
|
|
19
23
|
protected Binding: typeof AntDeviceBinding;
|
|
20
|
-
protected
|
|
21
|
-
protected isConnecting: boolean;
|
|
24
|
+
protected connectState: ConnectState;
|
|
22
25
|
protected props: AntInterfaceProps;
|
|
23
26
|
protected activeScan: IChannel;
|
|
24
27
|
constructor(props: AntInterfaceProps);
|
|
@@ -27,6 +30,7 @@ export default class AntInterface extends EventEmitter implements IncyclistInter
|
|
|
27
30
|
setBinding(binding: typeof AntDeviceBinding): void;
|
|
28
31
|
setLogger(logger: EventLogger): void;
|
|
29
32
|
logEvent(event: any): void;
|
|
33
|
+
isConnected(): boolean;
|
|
30
34
|
connect(): Promise<boolean>;
|
|
31
35
|
disconnect(): Promise<boolean>;
|
|
32
36
|
onError(profile: any, error: any): void;
|
|
@@ -28,8 +28,10 @@ class AntInterface extends events_1.default {
|
|
|
28
28
|
super();
|
|
29
29
|
this.props = props;
|
|
30
30
|
this.device = undefined;
|
|
31
|
-
this.
|
|
32
|
-
|
|
31
|
+
this.connectState = {
|
|
32
|
+
connected: false,
|
|
33
|
+
connecting: false
|
|
34
|
+
};
|
|
33
35
|
const { binding, logger } = props;
|
|
34
36
|
if (logger)
|
|
35
37
|
this.logger = logger;
|
|
@@ -56,38 +58,42 @@ class AntInterface extends events_1.default {
|
|
|
56
58
|
if (this.logger)
|
|
57
59
|
this.logger.logEvent(event);
|
|
58
60
|
}
|
|
61
|
+
isConnected() {
|
|
62
|
+
return this.connectState.connected;
|
|
63
|
+
}
|
|
59
64
|
connect() {
|
|
60
65
|
return __awaiter(this, void 0, void 0, function* () {
|
|
61
|
-
if (this.isConnected)
|
|
66
|
+
if (this.isConnected())
|
|
62
67
|
return true;
|
|
63
|
-
if (!this.
|
|
64
|
-
this.
|
|
68
|
+
if (!this.connectState.connecting) {
|
|
69
|
+
this.connectState.connecting = true;
|
|
65
70
|
this.logEvent({ message: 'ANT+ connecting ...' });
|
|
66
71
|
try {
|
|
67
72
|
const device = new this.Binding(Object.assign(Object.assign({}, this.props), { logger: this.logger }));
|
|
68
73
|
const opened = yield device.open();
|
|
69
74
|
if (!opened) {
|
|
70
75
|
this.logEvent({ message: 'ANT+ not connected' });
|
|
71
|
-
this.
|
|
76
|
+
this.connectState.connecting = false;
|
|
72
77
|
return false;
|
|
73
78
|
}
|
|
74
79
|
this.device = device;
|
|
75
|
-
this.
|
|
76
|
-
this.
|
|
80
|
+
this.connectState.connected = true;
|
|
81
|
+
this.connectState.connecting = false;
|
|
77
82
|
this.logEvent({ message: 'ANT+ connected' });
|
|
78
83
|
return true;
|
|
79
84
|
}
|
|
80
85
|
catch (err) {
|
|
81
|
-
this.
|
|
82
|
-
this.
|
|
86
|
+
this.logEvent({ message: 'error', fn: 'connect', error: err.message, stack: err.stack });
|
|
87
|
+
this.connectState.connected = false;
|
|
88
|
+
this.connectState.connecting = false;
|
|
83
89
|
return false;
|
|
84
90
|
}
|
|
85
91
|
}
|
|
86
92
|
else {
|
|
87
93
|
return new Promise(resolve => {
|
|
88
94
|
setInterval(() => {
|
|
89
|
-
if (!this.
|
|
90
|
-
resolve(this.
|
|
95
|
+
if (!this.connectState.connecting)
|
|
96
|
+
resolve(this.connectState.connected);
|
|
91
97
|
}, 500);
|
|
92
98
|
});
|
|
93
99
|
}
|
|
@@ -99,7 +105,7 @@ class AntInterface extends events_1.default {
|
|
|
99
105
|
return true;
|
|
100
106
|
this.logEvent({ message: 'ANT+ disconnecting ...' });
|
|
101
107
|
const closed = yield this.device.close();
|
|
102
|
-
this.
|
|
108
|
+
this.connectState.connected = !closed;
|
|
103
109
|
this.logEvent({ message: 'ANT+ disconnected' });
|
|
104
110
|
return closed;
|
|
105
111
|
});
|
|
@@ -114,16 +120,11 @@ class AntInterface extends events_1.default {
|
|
|
114
120
|
return __awaiter(this, void 0, void 0, function* () {
|
|
115
121
|
this.logEvent({ message: 'starting scan ..' });
|
|
116
122
|
const detected = [];
|
|
117
|
-
if (!this.isConnected) {
|
|
118
|
-
const connected = yield this.connect();
|
|
119
|
-
if (!connected)
|
|
120
|
-
return [];
|
|
121
|
-
}
|
|
122
123
|
const onDetected = (profile, deviceID) => {
|
|
123
124
|
if (deviceID && detected.find(s => s.deviceID === deviceID && s.profile === profile) === undefined) {
|
|
124
125
|
try {
|
|
125
126
|
detected.push({ interface: this.getName(), profile, deviceID });
|
|
126
|
-
this.emit('device', profile, deviceID);
|
|
127
|
+
this.emit('device', { interface: 'ant', profile, deviceID });
|
|
127
128
|
}
|
|
128
129
|
catch (err) {
|
|
129
130
|
this.logEvent({ message: 'error', fn: 'onDerected', error: err.message, stack: err.stack });
|
|
@@ -132,6 +133,11 @@ class AntInterface extends events_1.default {
|
|
|
132
133
|
};
|
|
133
134
|
let channel;
|
|
134
135
|
if (!this.activeScan) {
|
|
136
|
+
while (!this.isConnected()) {
|
|
137
|
+
const connected = yield this.connect();
|
|
138
|
+
if (!connected)
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
135
141
|
channel = this.device.getChannel();
|
|
136
142
|
channel.setProps({ logger: this.logger });
|
|
137
143
|
if (!channel)
|
|
@@ -204,7 +210,7 @@ class AntInterface extends events_1.default {
|
|
|
204
210
|
}
|
|
205
211
|
startSensor(sensor, onDeviceData) {
|
|
206
212
|
return __awaiter(this, void 0, void 0, function* () {
|
|
207
|
-
if (!this.isConnected) {
|
|
213
|
+
if (!this.isConnected()) {
|
|
208
214
|
const connected = yield this.connect();
|
|
209
215
|
if (!connected)
|
|
210
216
|
return false;
|
|
@@ -235,7 +241,7 @@ class AntInterface extends events_1.default {
|
|
|
235
241
|
}
|
|
236
242
|
stopSensor(sensor) {
|
|
237
243
|
return __awaiter(this, void 0, void 0, function* () {
|
|
238
|
-
if (!this.isConnected || !this.device)
|
|
244
|
+
if (!this.isConnected() || !this.device)
|
|
239
245
|
return true;
|
|
240
246
|
const channel = sensor.getChannel();
|
|
241
247
|
if (channel) {
|
package/lib/antv2/binding.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { IAntDevice, IChannel } from 'incyclist-ant-plus';
|
|
3
3
|
import { AntInterfaceProps } from './ant-interface';
|
|
4
4
|
export default class AntDeviceBinding implements IAntDevice {
|
|
5
|
-
constructor(
|
|
5
|
+
constructor(_props: AntInterfaceProps);
|
|
6
6
|
open(): Promise<boolean>;
|
|
7
7
|
close(): Promise<boolean>;
|
|
8
8
|
getMaxChannels(): number;
|
package/lib/antv2/binding.js
CHANGED
|
@@ -1,25 +1,28 @@
|
|
|
1
|
-
import { ISensor } from "incyclist-ant-plus";
|
|
1
|
+
import { FitnessEquipmentSensorState, ISensor, Profile } from "incyclist-ant-plus";
|
|
2
2
|
import { ControllableAntAdapter } from "../adapter";
|
|
3
|
-
import CyclingMode, { IncyclistBikeData } from '../../modes/cycling-mode';
|
|
4
|
-
import { AntDeviceProperties, AntDeviceSettings } from "../types";
|
|
3
|
+
import CyclingMode, { IncyclistBikeData, UpdateRequest } from '../../modes/cycling-mode';
|
|
4
|
+
import { AntDeviceProperties, AntDeviceSettings, LegacyProfile } from "../types";
|
|
5
5
|
export default class AntFEAdapter extends ControllableAntAdapter {
|
|
6
|
-
static INCYCLIST_PROFILE_NAME:
|
|
7
|
-
static ANT_PROFILE_NAME:
|
|
6
|
+
static INCYCLIST_PROFILE_NAME: LegacyProfile;
|
|
7
|
+
static ANT_PROFILE_NAME: Profile;
|
|
8
8
|
protected distanceInternal?: number;
|
|
9
9
|
protected startProps: AntDeviceProperties;
|
|
10
10
|
protected isReconnecting: boolean;
|
|
11
11
|
constructor(settings: AntDeviceSettings, props?: AntDeviceProperties);
|
|
12
12
|
createSensor(settings: AntDeviceSettings): ISensor;
|
|
13
13
|
getName(): string;
|
|
14
|
+
getUniqueName(): string;
|
|
14
15
|
getDisplayName(): string;
|
|
15
16
|
getSupportedCyclingModes(): Array<any>;
|
|
16
17
|
getDefaultCyclingMode(): CyclingMode;
|
|
17
18
|
getLogData(data: any, excludeList: any): any;
|
|
18
|
-
sendUpdate(request:
|
|
19
|
-
onDeviceData(deviceData:
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
sendUpdate(request: UpdateRequest, forced?: boolean): Promise<void>;
|
|
20
|
+
onDeviceData(deviceData: FitnessEquipmentSensorState): void;
|
|
21
|
+
canSendUpdate(): boolean;
|
|
22
|
+
mapToCycleModeData(deviceData: FitnessEquipmentSensorState): IncyclistBikeData;
|
|
23
|
+
transformData(bikeData: IncyclistBikeData): any;
|
|
22
24
|
start(props?: any): Promise<any>;
|
|
23
25
|
setFEDefaultTimeout(): void;
|
|
24
26
|
reconnect(): Promise<boolean>;
|
|
27
|
+
setCyclingMode(mode: string | CyclingMode, settings?: any): void;
|
|
25
28
|
}
|