incyclist-devices 1.4.24 → 1.4.27
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/lib/Device.d.ts +1 -1
- package/lib/Device.js +2 -2
- package/lib/DeviceProtocol.d.ts +3 -1
- package/lib/DeviceProtocol.js +2 -0
- package/lib/DeviceSupport.d.ts +6 -1
- package/lib/DeviceSupport.js +9 -0
- package/lib/ant/AntScanner.js +7 -5
- package/lib/ant/antfe/AntFEAdapter.js +0 -19
- package/lib/ant/anthrm/AntHrmAdapter.js +0 -11
- package/lib/ant/antpwr/pwr-adapter.js +0 -11
- package/lib/ble/ble-device.d.ts +36 -0
- package/lib/ble/ble-device.js +174 -0
- package/lib/ble/ble-interface.d.ts +51 -0
- package/lib/ble/ble-interface.js +330 -0
- package/lib/ble/ble.d.ts +81 -0
- package/lib/ble/ble.js +51 -0
- package/lib/ble/hrm.d.ts +48 -0
- package/lib/ble/hrm.js +128 -0
- package/lib/ble/incyclist-protocol.d.ts +31 -0
- package/lib/ble/incyclist-protocol.js +106 -0
- package/lib/ble/pwr.d.ts +32 -0
- package/lib/ble/pwr.js +96 -0
- package/lib/calculations.js +2 -3
- package/lib/daum/DaumAdapter.d.ts +4 -4
- package/lib/daum/DaumAdapter.js +24 -20
- package/lib/daum/DaumPowerMeterCyclingMode.d.ts +8 -0
- package/lib/daum/DaumPowerMeterCyclingMode.js +21 -0
- package/lib/daum/ERGCyclingMode.d.ts +3 -6
- package/lib/daum/ERGCyclingMode.js +15 -27
- package/lib/daum/classic/DaumClassicAdapter.js +1 -1
- package/lib/daum/premium/DaumClassicCyclingMode.d.ts +2 -2
- package/lib/daum/premium/DaumClassicCyclingMode.js +2 -2
- package/lib/daum/premium/DaumPremiumAdapter.js +1 -1
- package/lib/daum/premium/tcpserial.js +0 -1
- package/lib/modes/power-base.d.ts +20 -0
- package/lib/modes/power-base.js +70 -0
- package/lib/modes/power-meter.d.ts +12 -10
- package/lib/modes/power-meter.js +30 -46
- package/lib/modes/simulator.d.ts +27 -0
- package/lib/modes/simulator.js +118 -0
- package/lib/simulator/Simulator.js +3 -3
- package/package.json +2 -1
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
12
|
+
if (mod && mod.__esModule) return mod;
|
|
13
|
+
var result = {};
|
|
14
|
+
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
|
15
|
+
result["default"] = mod;
|
|
16
|
+
return result;
|
|
17
|
+
};
|
|
18
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
19
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
20
|
+
};
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
const gd_eventlog_1 = require("gd-eventlog");
|
|
23
|
+
const DeviceProtocol_1 = __importStar(require("../DeviceProtocol"));
|
|
24
|
+
const DeviceRegistry_1 = __importDefault(require("../DeviceRegistry"));
|
|
25
|
+
const ble_1 = require("./ble");
|
|
26
|
+
const ble_interface_1 = __importDefault(require("./ble-interface"));
|
|
27
|
+
const hrm_1 = __importStar(require("./hrm"));
|
|
28
|
+
const pwr_1 = __importDefault(require("./pwr"));
|
|
29
|
+
const supportedDeviceTypes = [hrm_1.default, pwr_1.default];
|
|
30
|
+
class BleProtocol extends DeviceProtocol_1.default {
|
|
31
|
+
constructor(binding) {
|
|
32
|
+
super();
|
|
33
|
+
const b = binding || BleProtocol._defaultBinding;
|
|
34
|
+
this.logger = new gd_eventlog_1.EventLogger('BLE');
|
|
35
|
+
this.ble = new ble_interface_1.default({ binding: b, logger: this.logger });
|
|
36
|
+
BleProtocol._instances.push(this);
|
|
37
|
+
}
|
|
38
|
+
static setDefaultBinding(binding) {
|
|
39
|
+
BleProtocol._defaultBinding = binding;
|
|
40
|
+
BleProtocol._instances.forEach((p) => {
|
|
41
|
+
if (p.ble && !p.ble.getBinding()) {
|
|
42
|
+
p.ble.setBinding(binding);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
setBinding(binding) {
|
|
47
|
+
if (this.ble)
|
|
48
|
+
this.ble.setBinding(binding);
|
|
49
|
+
}
|
|
50
|
+
createDevice(bleDevice) {
|
|
51
|
+
const fromDevice = bleDevice instanceof ble_1.BleDeviceClass;
|
|
52
|
+
const profile = bleDevice instanceof ble_1.BleDeviceClass ? bleDevice.getProfile() : bleDevice.profile;
|
|
53
|
+
const props = () => {
|
|
54
|
+
const { id, name, address } = bleDevice;
|
|
55
|
+
return { id, name, address };
|
|
56
|
+
};
|
|
57
|
+
switch (profile.toLocaleLowerCase()) {
|
|
58
|
+
case 'hr':
|
|
59
|
+
case 'heartrate monitor':
|
|
60
|
+
return new hrm_1.HrmAdapter(fromDevice ? bleDevice : new hrm_1.default(props()), this);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
getName() { return 'BLE'; }
|
|
64
|
+
getInterfaces() { return [DeviceProtocol_1.INTERFACE.BLE]; }
|
|
65
|
+
isBike() { return true; }
|
|
66
|
+
isHrm() { return true; }
|
|
67
|
+
isPower() { return true; }
|
|
68
|
+
add(settings) {
|
|
69
|
+
this.logger.logEvent({ message: 'adding device', settings });
|
|
70
|
+
const device = this.createDevice(settings);
|
|
71
|
+
return device;
|
|
72
|
+
}
|
|
73
|
+
scan(props) {
|
|
74
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
75
|
+
try {
|
|
76
|
+
this.ble.on('device', (bleDevice) => {
|
|
77
|
+
if (props && props.onDeviceFound) {
|
|
78
|
+
const device = this.createDevice(bleDevice);
|
|
79
|
+
props.onDeviceFound(device, this);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
this.logger.logEvent({ message: 'scan started' });
|
|
83
|
+
yield this.ble.scan({ deviceTypes: supportedDeviceTypes });
|
|
84
|
+
if (props && props.onScanFinished) {
|
|
85
|
+
props.onScanFinished(props.id);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
this.logger.logEvent({ message: 'error', error: err.message });
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
stopScan() {
|
|
94
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
95
|
+
yield this.ble.stopScan();
|
|
96
|
+
return;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
isScanning() {
|
|
100
|
+
return this.ble.isScanning();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.default = BleProtocol;
|
|
104
|
+
BleProtocol._defaultBinding = undefined;
|
|
105
|
+
BleProtocol._instances = [];
|
|
106
|
+
DeviceRegistry_1.default.register(new BleProtocol());
|
package/lib/ble/pwr.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { BleDevice } from './ble-device';
|
|
3
|
+
declare type PowerData = {
|
|
4
|
+
instantaneousPower?: number;
|
|
5
|
+
balance?: number;
|
|
6
|
+
accTorque?: number;
|
|
7
|
+
rpm: number;
|
|
8
|
+
raw?: Buffer;
|
|
9
|
+
};
|
|
10
|
+
declare type CrankData = {
|
|
11
|
+
revolutions?: number;
|
|
12
|
+
time?: number;
|
|
13
|
+
cntUpdateMissing?: number;
|
|
14
|
+
};
|
|
15
|
+
export default class BleCyclingPowerDevice extends BleDevice {
|
|
16
|
+
static services: string[];
|
|
17
|
+
static characteristics: string[];
|
|
18
|
+
instantaneousPower: number;
|
|
19
|
+
balance: number;
|
|
20
|
+
accTorque: number;
|
|
21
|
+
currentCrankData: CrankData;
|
|
22
|
+
prevCrankData: CrankData;
|
|
23
|
+
rpm: number;
|
|
24
|
+
getProfile(): string;
|
|
25
|
+
getServiceUUids(): string[];
|
|
26
|
+
getRpm(crankData: any): number;
|
|
27
|
+
parsePower(data: Buffer): PowerData;
|
|
28
|
+
onData(characteristic: string, data: Buffer): void;
|
|
29
|
+
write(characteristic: any, data: any): Promise<boolean>;
|
|
30
|
+
read(characteristic: any): Promise<Buffer>;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
package/lib/ble/pwr.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
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 ble_device_1 = require("./ble-device");
|
|
7
|
+
const ble_interface_1 = __importDefault(require("./ble-interface"));
|
|
8
|
+
class BleCyclingPowerDevice extends ble_device_1.BleDevice {
|
|
9
|
+
constructor() {
|
|
10
|
+
super(...arguments);
|
|
11
|
+
this.instantaneousPower = undefined;
|
|
12
|
+
this.balance = undefined;
|
|
13
|
+
this.accTorque = undefined;
|
|
14
|
+
this.currentCrankData = undefined;
|
|
15
|
+
this.prevCrankData = undefined;
|
|
16
|
+
this.rpm = undefined;
|
|
17
|
+
}
|
|
18
|
+
getProfile() {
|
|
19
|
+
return 'cp';
|
|
20
|
+
}
|
|
21
|
+
getServiceUUids() {
|
|
22
|
+
return BleCyclingPowerDevice.services;
|
|
23
|
+
}
|
|
24
|
+
getRpm(crankData) {
|
|
25
|
+
if (!this.prevCrankData)
|
|
26
|
+
this.prevCrankData = { revolutions: 0, time: 0, cntUpdateMissing: -1 };
|
|
27
|
+
const c = this.currentCrankData = crankData;
|
|
28
|
+
const p = this.prevCrankData;
|
|
29
|
+
let rpm = this.rpm;
|
|
30
|
+
let hasUpdate = c.time !== p.time;
|
|
31
|
+
if (hasUpdate) {
|
|
32
|
+
let time = c.time - p.time;
|
|
33
|
+
let revs = c.revolutions - p.revolutions;
|
|
34
|
+
if (c.time < p.time)
|
|
35
|
+
time += 0x10000;
|
|
36
|
+
if (c.revolutions < p.revolutions)
|
|
37
|
+
revs += 0x10000;
|
|
38
|
+
rpm = 1024 * 60 * revs / time;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
if (p.cntUpdateMissing < 0 || p.cntUpdateMissing > 2) {
|
|
42
|
+
rpm = 0;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const cntUpdateMissing = p.cntUpdateMissing;
|
|
46
|
+
this.prevCrankData = this.currentCrankData;
|
|
47
|
+
if (hasUpdate)
|
|
48
|
+
this.prevCrankData.cntUpdateMissing = 0;
|
|
49
|
+
else
|
|
50
|
+
this.prevCrankData.cntUpdateMissing = cntUpdateMissing + 1;
|
|
51
|
+
return rpm;
|
|
52
|
+
}
|
|
53
|
+
parsePower(data) {
|
|
54
|
+
try {
|
|
55
|
+
let offset = 4;
|
|
56
|
+
const flags = data.readUInt16LE(0);
|
|
57
|
+
this.instantaneousPower = data.readUInt16LE(2);
|
|
58
|
+
if (flags & 0x1)
|
|
59
|
+
this.balance = data.readUInt8(offset++);
|
|
60
|
+
if (flags & 0x4) {
|
|
61
|
+
this.accTorque = data.readUInt16LE(offset);
|
|
62
|
+
offset += 2;
|
|
63
|
+
}
|
|
64
|
+
if (flags & 0x20) {
|
|
65
|
+
const crankData = {
|
|
66
|
+
revolutions: data.readUInt16LE(offset),
|
|
67
|
+
time: data.readUInt16LE(offset + 2)
|
|
68
|
+
};
|
|
69
|
+
this.rpm = this.getRpm(crankData);
|
|
70
|
+
offset += 4;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
}
|
|
75
|
+
const { instantaneousPower, balance, accTorque, rpm } = this;
|
|
76
|
+
return { instantaneousPower, balance, accTorque, rpm, raw: data };
|
|
77
|
+
}
|
|
78
|
+
onData(characteristic, data) {
|
|
79
|
+
if (characteristic.toLocaleLowerCase() === '2a63') {
|
|
80
|
+
const res = this.parsePower(data);
|
|
81
|
+
this.emit('data', res);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
write(characteristic, data) {
|
|
85
|
+
console.log('write', characteristic, data);
|
|
86
|
+
return Promise.resolve(true);
|
|
87
|
+
}
|
|
88
|
+
read(characteristic) {
|
|
89
|
+
console.log('read', characteristic);
|
|
90
|
+
return Promise.resolve(Buffer.from([]));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
exports.default = BleCyclingPowerDevice;
|
|
94
|
+
BleCyclingPowerDevice.services = ['1818'];
|
|
95
|
+
BleCyclingPowerDevice.characteristics = ['2a63', '2a65', '2a5d', '2a3c'];
|
|
96
|
+
ble_interface_1.default.register('BleCyclingPowerDevice', 'cp', BleCyclingPowerDevice, BleCyclingPowerDevice.services);
|
package/lib/calculations.js
CHANGED
|
@@ -7,7 +7,6 @@ const cwABike = {
|
|
|
7
7
|
triathlon: 0.29,
|
|
8
8
|
mountain: 0.57
|
|
9
9
|
};
|
|
10
|
-
const k = 0.01090;
|
|
11
10
|
const cRR = 0.0036;
|
|
12
11
|
class IllegalArgumentException extends Error {
|
|
13
12
|
constructor(message) {
|
|
@@ -28,7 +27,7 @@ class C {
|
|
|
28
27
|
const _cRR = props.cRR || cRR;
|
|
29
28
|
const _cwA = props.cwA || cwABike[props.bikeType || 'race'] || cwABike.race;
|
|
30
29
|
let sl = Math.atan(slope / 100);
|
|
31
|
-
let c1 = 0.5 * _rho * _cwA
|
|
30
|
+
let c1 = 0.5 * _rho * _cwA;
|
|
32
31
|
let c2 = (sl + _cRR) * m * g;
|
|
33
32
|
let p = c2 / c1;
|
|
34
33
|
let q = -1.0 * power / c1;
|
|
@@ -70,7 +69,7 @@ class C {
|
|
|
70
69
|
let _cRR = props.cRR || cRR;
|
|
71
70
|
let _cwA = props.cwA || cwABike[props.bikeType || 'race'] || cwABike.race;
|
|
72
71
|
let sl = Math.sin(Math.atan(slope / 100));
|
|
73
|
-
let P = (0.5 * _rho * _cwA
|
|
72
|
+
let P = (0.5 * _rho * _cwA) * Math.pow(v, 3.0) + (sl + _cRR) * m * g * v;
|
|
74
73
|
return P;
|
|
75
74
|
}
|
|
76
75
|
static calculateSpeedDaum(gear, rpm, bikeType) {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { EventLogger } from 'gd-eventlog';
|
|
2
2
|
import CyclingMode, { IncyclistBikeData } from '../CyclingMode';
|
|
3
|
-
import
|
|
3
|
+
import IncyclistDevice, { Bike, DeviceAdapter, DeviceData } from '../Device';
|
|
4
4
|
import { User } from '../types/user';
|
|
5
5
|
interface DaumAdapter {
|
|
6
6
|
getCurrentBikeData(): Promise<any>;
|
|
7
7
|
}
|
|
8
|
-
export default class DaumAdapterBase extends
|
|
8
|
+
export default class DaumAdapterBase extends IncyclistDevice implements DeviceAdapter, DaumAdapter, Bike {
|
|
9
9
|
bike: any;
|
|
10
10
|
ignoreHrm: boolean;
|
|
11
11
|
ignoreBike: boolean;
|
|
@@ -13,7 +13,7 @@ export default class DaumAdapterBase extends DeviceAdapterBase implements Device
|
|
|
13
13
|
distanceInternal: number;
|
|
14
14
|
paused: boolean;
|
|
15
15
|
stopped: boolean;
|
|
16
|
-
|
|
16
|
+
cyclingData: IncyclistBikeData;
|
|
17
17
|
deviceData: DeviceData;
|
|
18
18
|
currentRequest: any;
|
|
19
19
|
requests: Array<any>;
|
|
@@ -56,7 +56,7 @@ export default class DaumAdapterBase extends DeviceAdapterBase implements Device
|
|
|
56
56
|
update(): Promise<void>;
|
|
57
57
|
sendRequests(): Promise<void>;
|
|
58
58
|
bikeSync(): Promise<void>;
|
|
59
|
-
updateData(prev: any, bikeData: any):
|
|
59
|
+
updateData(prev: any, bikeData: any): IncyclistBikeData;
|
|
60
60
|
transformData(): DeviceData;
|
|
61
61
|
sendRequest(request: any): Promise<any>;
|
|
62
62
|
refreshRequests(): void;
|
package/lib/daum/DaumAdapter.js
CHANGED
|
@@ -22,7 +22,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
22
22
|
const Device_1 = __importStar(require("../Device"));
|
|
23
23
|
const ERGCyclingMode_1 = __importDefault(require("./ERGCyclingMode"));
|
|
24
24
|
const SmartTrainerCyclingMode_1 = __importDefault(require("./SmartTrainerCyclingMode"));
|
|
25
|
-
const
|
|
25
|
+
const DaumPowerMeterCyclingMode_1 = __importDefault(require("./DaumPowerMeterCyclingMode"));
|
|
26
26
|
const utils_1 = require("../utils");
|
|
27
27
|
class DaumAdapterBase extends Device_1.default {
|
|
28
28
|
constructor(props, bike) {
|
|
@@ -34,7 +34,7 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
34
34
|
this.bike = bike;
|
|
35
35
|
this.stopped = false;
|
|
36
36
|
this.paused = false;
|
|
37
|
-
this.
|
|
37
|
+
this.cyclingData = {
|
|
38
38
|
isPedalling: false,
|
|
39
39
|
time: 0,
|
|
40
40
|
power: 0,
|
|
@@ -67,7 +67,7 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
67
67
|
this.cyclingMode.setSettings(settings);
|
|
68
68
|
}
|
|
69
69
|
getSupportedCyclingModes() {
|
|
70
|
-
return [ERGCyclingMode_1.default, SmartTrainerCyclingMode_1.default,
|
|
70
|
+
return [ERGCyclingMode_1.default, SmartTrainerCyclingMode_1.default, DaumPowerMeterCyclingMode_1.default];
|
|
71
71
|
}
|
|
72
72
|
getCyclingMode() {
|
|
73
73
|
if (!this.cyclingMode)
|
|
@@ -128,7 +128,7 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
128
128
|
this.distanceInternal = undefined;
|
|
129
129
|
this.paused = false;
|
|
130
130
|
this.stopped = false;
|
|
131
|
-
this.
|
|
131
|
+
this.cyclingData = {
|
|
132
132
|
isPedalling: false,
|
|
133
133
|
time: 0,
|
|
134
134
|
power: 0,
|
|
@@ -229,12 +229,15 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
229
229
|
this.updateBusy = true;
|
|
230
230
|
this.getCurrentBikeData()
|
|
231
231
|
.then(bikeData => {
|
|
232
|
-
this.updateData(this.
|
|
232
|
+
this.updateData(this.cyclingData, bikeData);
|
|
233
233
|
this.transformData();
|
|
234
234
|
this.updateBusy = false;
|
|
235
235
|
})
|
|
236
236
|
.catch(err => {
|
|
237
237
|
this.logEvent({ message: 'bike update error', error: err.message, stack: err.stack });
|
|
238
|
+
const { isPedalling, power, pedalRpm, speed, distanceInternal, heartrate, slope } = this.cyclingData;
|
|
239
|
+
this.updateData(this.cyclingData, { isPedalling, power, pedalRpm, speed, distanceInternal, heartrate, slope });
|
|
240
|
+
this.transformData();
|
|
238
241
|
this.updateBusy = false;
|
|
239
242
|
});
|
|
240
243
|
});
|
|
@@ -289,27 +292,28 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
289
292
|
data.time = bikeData.time;
|
|
290
293
|
if (bikeData.slope)
|
|
291
294
|
data.slope = bikeData.slope;
|
|
292
|
-
this.
|
|
295
|
+
this.cyclingData = this.getCyclingMode().updateData(data);
|
|
296
|
+
return this.cyclingData;
|
|
293
297
|
}
|
|
294
298
|
transformData() {
|
|
295
|
-
if (this.
|
|
299
|
+
if (this.cyclingData === undefined)
|
|
296
300
|
return;
|
|
297
301
|
let distance = 0;
|
|
298
|
-
if (this.distanceInternal !== undefined && this.
|
|
299
|
-
distance = utils_1.intVal(this.
|
|
302
|
+
if (this.distanceInternal !== undefined && this.cyclingData.distanceInternal !== undefined) {
|
|
303
|
+
distance = utils_1.intVal(this.cyclingData.distanceInternal - this.distanceInternal);
|
|
300
304
|
}
|
|
301
|
-
if (this.
|
|
302
|
-
this.distanceInternal = this.
|
|
305
|
+
if (this.cyclingData.distanceInternal !== undefined)
|
|
306
|
+
this.distanceInternal = this.cyclingData.distanceInternal;
|
|
303
307
|
let data = {
|
|
304
|
-
speed: utils_1.floatVal(this.
|
|
305
|
-
slope: utils_1.floatVal(this.
|
|
306
|
-
power: utils_1.intVal(this.
|
|
307
|
-
cadence: utils_1.intVal(this.
|
|
308
|
-
heartrate: utils_1.intVal(this.
|
|
308
|
+
speed: utils_1.floatVal(this.cyclingData.speed),
|
|
309
|
+
slope: utils_1.floatVal(this.cyclingData.slope),
|
|
310
|
+
power: utils_1.intVal(this.cyclingData.power),
|
|
311
|
+
cadence: utils_1.intVal(this.cyclingData.pedalRpm),
|
|
312
|
+
heartrate: utils_1.intVal(this.cyclingData.heartrate),
|
|
309
313
|
distance,
|
|
310
314
|
timestamp: Date.now(),
|
|
311
|
-
deviceTime: this.
|
|
312
|
-
deviceDistanceCounter: this.
|
|
315
|
+
deviceTime: this.cyclingData.time,
|
|
316
|
+
deviceDistanceCounter: this.cyclingData.distanceInternal
|
|
313
317
|
};
|
|
314
318
|
if (this.ignoreHrm)
|
|
315
319
|
delete data.heartrate;
|
|
@@ -350,7 +354,7 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
350
354
|
});
|
|
351
355
|
}
|
|
352
356
|
refreshRequests() {
|
|
353
|
-
if (!this.
|
|
357
|
+
if (!this.cyclingData.isPedalling || this.cyclingData.pedalRpm === 0)
|
|
354
358
|
return;
|
|
355
359
|
let bikeRequest = this.getCyclingMode().sendBikeUpdate({ refresh: true }) || {};
|
|
356
360
|
const prev = this.requests[this.requests.length - 1] || {};
|
|
@@ -361,7 +365,7 @@ class DaumAdapterBase extends Device_1.default {
|
|
|
361
365
|
}
|
|
362
366
|
processClientRequest(request) {
|
|
363
367
|
if (request.slope !== undefined) {
|
|
364
|
-
this.
|
|
368
|
+
this.cyclingData.slope = request.slope;
|
|
365
369
|
}
|
|
366
370
|
return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
367
371
|
let bikeRequest = this.getCyclingMode().sendBikeUpdate(request);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import CyclingMode, { UpdateRequest } from "../CyclingMode";
|
|
2
|
+
import PowerMeterCyclingMode from "../modes/power-meter";
|
|
3
|
+
export default class DaumPowerMeterCyclingMode extends PowerMeterCyclingMode implements CyclingMode {
|
|
4
|
+
prevRequest: UpdateRequest;
|
|
5
|
+
hasBikeUpdate: boolean;
|
|
6
|
+
getBikeInitRequest(): UpdateRequest;
|
|
7
|
+
sendBikeUpdate(request: UpdateRequest): UpdateRequest;
|
|
8
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
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 power_meter_1 = __importDefault(require("../modes/power-meter"));
|
|
7
|
+
class DaumPowerMeterCyclingMode extends power_meter_1.default {
|
|
8
|
+
constructor() {
|
|
9
|
+
super(...arguments);
|
|
10
|
+
this.hasBikeUpdate = false;
|
|
11
|
+
}
|
|
12
|
+
getBikeInitRequest() {
|
|
13
|
+
return { slope: 0 };
|
|
14
|
+
}
|
|
15
|
+
sendBikeUpdate(request) {
|
|
16
|
+
super.sendBikeUpdate(request);
|
|
17
|
+
this.prevRequest = {};
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.default = DaumPowerMeterCyclingMode;
|
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import CyclingMode, { CyclingModeBase, CyclingModeProperty, IncyclistBikeData, UpdateRequest } from "../CyclingMode";
|
|
1
|
+
import CyclingMode, { CyclingModeProperty, IncyclistBikeData, UpdateRequest } from "../CyclingMode";
|
|
3
2
|
import DaumAdapter from "./DaumAdapter";
|
|
3
|
+
import PowerBasedCyclingModeBase from "../modes/power-base";
|
|
4
4
|
export declare type ERGEvent = {
|
|
5
5
|
rpmUpdated?: boolean;
|
|
6
6
|
gearUpdated?: boolean;
|
|
7
7
|
starting?: boolean;
|
|
8
8
|
tsStart?: number;
|
|
9
9
|
};
|
|
10
|
-
export default class ERGCyclingMode extends
|
|
11
|
-
logger: EventLogger;
|
|
12
|
-
data: IncyclistBikeData;
|
|
10
|
+
export default class ERGCyclingMode extends PowerBasedCyclingModeBase implements CyclingMode {
|
|
13
11
|
prevRequest: UpdateRequest;
|
|
14
|
-
prevUpdateTS: number;
|
|
15
12
|
hasBikeUpdate: boolean;
|
|
16
13
|
chain: number[];
|
|
17
14
|
cassette: number[];
|
|
@@ -3,9 +3,9 @@ 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
|
-
const gd_eventlog_1 = require("gd-eventlog");
|
|
7
6
|
const CyclingMode_1 = require("../CyclingMode");
|
|
8
7
|
const calculations_1 = __importDefault(require("../calculations"));
|
|
8
|
+
const power_base_1 = __importDefault(require("../modes/power-base"));
|
|
9
9
|
const config = {
|
|
10
10
|
name: "ERG",
|
|
11
11
|
description: "Calculates speed based on power and slope. Power is either set by workout or calculated based on gear and cadence",
|
|
@@ -14,15 +14,12 @@ const config = {
|
|
|
14
14
|
{ 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 },
|
|
15
15
|
]
|
|
16
16
|
};
|
|
17
|
-
class ERGCyclingMode extends
|
|
17
|
+
class ERGCyclingMode extends power_base_1.default {
|
|
18
18
|
constructor(adapter, props) {
|
|
19
19
|
super(adapter, props);
|
|
20
|
-
this.prevUpdateTS = 0;
|
|
21
20
|
this.hasBikeUpdate = false;
|
|
22
21
|
this.event = {};
|
|
23
|
-
this.
|
|
24
|
-
this.data = {};
|
|
25
|
-
this.logger.logEvent({ message: 'constructor', props });
|
|
22
|
+
this.initLogger('ERGMode');
|
|
26
23
|
}
|
|
27
24
|
getName() {
|
|
28
25
|
return config.name;
|
|
@@ -132,7 +129,6 @@ class ERGCyclingMode extends CyclingMode_1.CyclingModeBase {
|
|
|
132
129
|
const prevRequest = this.prevRequest || {};
|
|
133
130
|
const data = this.data || {};
|
|
134
131
|
const bikeType = this.getSetting('bikeType').toLowerCase();
|
|
135
|
-
console.log('~~~ bikeType', bikeType);
|
|
136
132
|
delete this.event.gearUpdated;
|
|
137
133
|
delete this.event.rpmUpdated;
|
|
138
134
|
if (prevData === {} || prevData.speed === undefined || prevData.speed === 0) {
|
|
@@ -140,32 +136,25 @@ class ERGCyclingMode extends CyclingMode_1.CyclingModeBase {
|
|
|
140
136
|
this.event.tsStart = Date.now();
|
|
141
137
|
}
|
|
142
138
|
try {
|
|
143
|
-
|
|
144
|
-
|
|
139
|
+
const rpm = bikeData.pedalRpm || 0;
|
|
140
|
+
const gear = bikeData.gear || 0;
|
|
145
141
|
let power = bikeData.power || 0;
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
let distanceInternal = prevData.distanceInternal || 0;
|
|
150
|
-
let ts = Date.now();
|
|
151
|
-
let duration = this.prevUpdateTS === 0 ? 0 : ((ts - this.prevUpdateTS) / 1000);
|
|
152
|
-
if (rpm === 0 || bikeData.isPedalling === false) {
|
|
153
|
-
speed = 0;
|
|
142
|
+
const slope = (prevData.slope !== undefined ? prevData.slope : prevRequest.slope || 0);
|
|
143
|
+
const distanceInternal = prevData.distanceInternal || 0;
|
|
144
|
+
if (!bikeData.pedalRpm || bikeData.isPedalling === false) {
|
|
154
145
|
power = 0;
|
|
155
146
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
distanceInternal += Math.round(v * duration);
|
|
160
|
-
}
|
|
147
|
+
const m = this.getWeight();
|
|
148
|
+
const t = this.getTimeSinceLastUpdate();
|
|
149
|
+
const { speed, distance } = this.calculateSpeedAndDistance(power, slope, m, t, { bikeType });
|
|
161
150
|
data.speed = parseFloat(speed.toFixed(1));
|
|
162
151
|
data.power = Math.round(power);
|
|
163
|
-
data.distanceInternal = distanceInternal;
|
|
152
|
+
data.distanceInternal = Math.round(distanceInternal + distance);
|
|
164
153
|
data.slope = slope;
|
|
165
154
|
data.pedalRpm = rpm;
|
|
166
155
|
data.gear = gear;
|
|
167
|
-
if (data.time !== undefined)
|
|
168
|
-
data.time +=
|
|
156
|
+
if (data.time !== undefined && !(this.event.starting && !bikeData.pedalRpm))
|
|
157
|
+
data.time += t;
|
|
169
158
|
else
|
|
170
159
|
data.time = 0;
|
|
171
160
|
data.heartrate = bikeData.heartrate;
|
|
@@ -176,7 +165,6 @@ class ERGCyclingMode extends CyclingMode_1.CyclingModeBase {
|
|
|
176
165
|
if (rpm && rpm !== prevData.pedalRpm) {
|
|
177
166
|
this.event.rpmUpdated = true;
|
|
178
167
|
}
|
|
179
|
-
this.prevUpdateTS = ts;
|
|
180
168
|
}
|
|
181
169
|
catch (err) {
|
|
182
170
|
this.logger.logEvent({ message: 'error', fn: 'updateData()', error: err.message || err });
|
|
@@ -188,7 +176,7 @@ class ERGCyclingMode extends CyclingMode_1.CyclingModeBase {
|
|
|
188
176
|
calculateTargetPower(request, updateMode = true) {
|
|
189
177
|
const bikeType = this.getSetting('bikeType').toLowerCase();
|
|
190
178
|
const defaultPower = this.getSetting('startPower');
|
|
191
|
-
let m = this.
|
|
179
|
+
let m = this.getWeight();
|
|
192
180
|
const prevData = this.data || {};
|
|
193
181
|
let target;
|
|
194
182
|
if (prevData.pedalRpm && prevData.gear && (!updateMode || prevData.pedalRpm !== 0)) {
|
|
@@ -109,7 +109,7 @@ class DaumClassicAdapter extends DaumAdapter_1.default {
|
|
|
109
109
|
startState.startProg = true;
|
|
110
110
|
}
|
|
111
111
|
if (!startState.setGear) {
|
|
112
|
-
yield this.bike.setGear(this.
|
|
112
|
+
yield this.bike.setGear(this.cyclingData.gear || (opts.gear || 10));
|
|
113
113
|
startState.setGear = true;
|
|
114
114
|
}
|
|
115
115
|
const startRequest = this.getCyclingMode().getBikeInitRequest();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import CyclingMode, { CyclingModeProperty, IncyclistBikeData, Settings, UpdateRequest } from "../../CyclingMode";
|
|
2
2
|
import DaumAdapter from "../DaumAdapter";
|
|
3
|
-
import
|
|
4
|
-
export default class DaumClassicCyclingMode extends
|
|
3
|
+
import DaumPowerMeterCyclingMode from "../DaumPowerMeterCyclingMode";
|
|
4
|
+
export default class DaumClassicCyclingMode extends DaumPowerMeterCyclingMode implements CyclingMode {
|
|
5
5
|
constructor(adapter: DaumAdapter, props?: Settings);
|
|
6
6
|
getName(): string;
|
|
7
7
|
getDescription(): string;
|
|
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const gd_eventlog_1 = require("gd-eventlog");
|
|
7
7
|
const CyclingMode_1 = require("../../CyclingMode");
|
|
8
|
-
const
|
|
8
|
+
const DaumPowerMeterCyclingMode_1 = __importDefault(require("../DaumPowerMeterCyclingMode"));
|
|
9
9
|
const config = {
|
|
10
10
|
name: "Daum Classic",
|
|
11
11
|
description: "The device calculates speed and power based on slope. Incyclist will not modify any values recived from the device\nThis mode will not respect maximum power and/or workout limits",
|
|
@@ -13,7 +13,7 @@ const config = {
|
|
|
13
13
|
{ key: 'bikeType', name: 'Bike Type', description: '', type: CyclingMode_1.CyclingModeProperyType.SingleSelect, options: ['Race', 'Mountain'], default: 'Race' },
|
|
14
14
|
]
|
|
15
15
|
};
|
|
16
|
-
class DaumClassicCyclingMode extends
|
|
16
|
+
class DaumClassicCyclingMode extends DaumPowerMeterCyclingMode_1.default {
|
|
17
17
|
constructor(adapter, props) {
|
|
18
18
|
super(adapter, props);
|
|
19
19
|
this.logger = adapter ? adapter.logger : undefined;
|
|
@@ -98,7 +98,7 @@ class DaumPremiumDevice extends DaumAdapter_1.default {
|
|
|
98
98
|
info.person = yield this.bike.setPerson(user);
|
|
99
99
|
}
|
|
100
100
|
if (!this.getCyclingMode().getModeProperty('eppSupport')) {
|
|
101
|
-
const gear = yield this.bike.setGear(this.
|
|
101
|
+
const gear = yield this.bike.setGear(this.cyclingData.gear || (opts.gear || 10));
|
|
102
102
|
return gear;
|
|
103
103
|
}
|
|
104
104
|
return;
|
|
@@ -5,7 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const net_1 = __importDefault(require("net"));
|
|
7
7
|
const gd_eventlog_1 = require("gd-eventlog");
|
|
8
|
-
const TIMEOUT_OPEN = 1000;
|
|
9
8
|
var __responses = {};
|
|
10
9
|
class TcpSocketPort {
|
|
11
10
|
constructor(props) {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { IncyclistBikeData, Settings, CyclingModeBase } from '../CyclingMode';
|
|
2
|
+
import { DeviceAdapter } from '../Device';
|
|
3
|
+
import { EventLogger } from 'gd-eventlog';
|
|
4
|
+
export default class PowerBasedCyclingModeBase extends CyclingModeBase {
|
|
5
|
+
data: IncyclistBikeData;
|
|
6
|
+
prevUpdateTS: number;
|
|
7
|
+
logger: EventLogger;
|
|
8
|
+
constructor(adapter: DeviceAdapter, props?: Settings);
|
|
9
|
+
initLogger(defaultLogName: any): void;
|
|
10
|
+
getWeight(): any;
|
|
11
|
+
getTimeSinceLastUpdate(): number;
|
|
12
|
+
calculateSpeedAndDistance(power: number, slope: number, m: number, t: number, props?: {}): {
|
|
13
|
+
speed: number;
|
|
14
|
+
distance: number;
|
|
15
|
+
};
|
|
16
|
+
calculatePowerAndDistance(speed: number, slope: number, m: number, t: number, props?: {}): {
|
|
17
|
+
power: number;
|
|
18
|
+
distance: number;
|
|
19
|
+
};
|
|
20
|
+
}
|