-
Notifications
You must be signed in to change notification settings - Fork 4
/
index.js
147 lines (131 loc) · 4.72 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Setup multi role support and two different adapters for Peripheral and Central
process.env['NOBLE_MULTI_ROLE'] = 1
process.env['NOBLE_REPORT_ALL_HCI_EVENTS'] = 1
process.env['BLENO_HCI_DEVICE_ID'] = 0
process.env['NOBLE_HCI_DEVICE_ID'] = 0
const noble = require('@abandonware/noble');
const keiserParser = require('./keiserParser.js');
const KeiserBLE = require('./BLE/keiserBLE');
const { createServer } = require('http');
const fs = require('fs');
var result = null;
var fillInTimer = null;
var dataToSend = null;
var connectedCount = 0;
var targetDeviceId = -1;
var cranks = 0;
var cranksLastEventTime = 0;
console.log("Starting");
var keiserBLE = new KeiserBLE();
keiserBLE.on('advertisingStart', (client) => {
//oled.displayBLE('Started');
});
keiserBLE.on('accept', (client) => {
connectedCount++;
//oled.displayBLE('Connected');
});
keiserBLE.on('disconnect', (client) => {
connectedCount--;
//oled.displayBLE('Disconnected');
});
noble.on('stateChange', async (state) => {
console.log(`[Central] State changed to ${state}`);
if (state === 'poweredOn') {
console.log(`[Central] starting scan`);
await noble.startScanningAsync(null, true);
} else if (state === 'poweredOff') {
console.log('No adapter detected, exiting in 5 seconds');
setTimeout(() => {
process.exit();
}, 5000);
}
});
noble.on('scanStop', async () => {
console.log("Restarting BLE Scan");
try {
await noble.startScanningAsync(null, true);
} catch (err) {
console.log("Unable to restart BLE Scan: " + err);
}
});
function sendFillInData() {
if (!dataToSend || (connectedCount < 1)) {
console.log("Aborting nothing to send");
} else {
console.log("Sending fill in data");
keiserBLE.notifyClient(dataToSend);
fillInTimer = setTimeout(sendFillInData, 1000);
}
};
createServer((req, res) => {
if (result) {
res.writeHead(200, { 'Content-Type': 'text/html' })
res.end(`
<h1 style="font-family:verdana;">${result.realTime ? "Keiser in in use" : "Summary Data" }</h1>
<h1 style="font-family:verdana;">=======================</h1>
<h1 style="font-family:verdana;">Cadence: ${result.cadence} rpms</h1>
<h1 style="font-family:verdana;">Power: ${result.power} watts</h1>
<h1 style="font-family:verdana;">Gear: ${result.gear}</h1>
<h1 style="font-family:verdana;">Duration: ${Math.floor(result.duration/60)} minutes ${result.duration % 60} seconds </h1>`);
} else {
res.writeHead(200, { 'Content-Type': 'text/html' })
res.end(`
<h1 style="font-family:verdana;">No Data</h1>`);
}
}).listen(3000, () => console.log('server running - 3000'));
noble.on('discover', (peripheral) => {
//console.log(`[Central] Found device ${peripheral.advertisement.localName} ${peripheral.address}`);
if (peripheral.advertisement.localName == "M3") {
try {
result = keiserParser.parseAdvertisement(peripheral);
console.log(`Bike ${result.ordinalId}: RT: ${result.realTime} RPM: ${result.cadence} PWR: ${result.power} HR:${result.heartRate} GEAR: ${result.gear} ET: ${result.duration}`);
// Only continue if M3i is transmitting real-time data
if (result.realTime) {
// Only use data coming from target device; if no target device set then set it
if (result.ordinalId != targetDeviceId) {
if (targetDeviceId == -1) {
console.log(`Attaching to bike id ${result.ordinalId}`);
targetDeviceId = result.ordinalId;
keiserBLE.setDeviceId(targetDeviceId);
} else {
return;
}
}
// Use current rpm (cadence) to simulate the crank count and crank event time for CPS and CSC services
// (for range of valid values for crank count and crank event time, see BLE specs)
if (result.cadence > 0) {
var cranksCurrentEventTime = (cranksLastEventTime + Math.round((60 * 1024)/result.cadence)) % 65535;
cranks++;
} else {
var cranksCurrentEventTime = cranksLastEventTime;
}
// Assemble the data structure for the BLE service/characteristics to use
dataToSend = {
rpm: result.cadence,
ftmsrpm: result.ftmscadence,
power: result.power,
hr: result.heartRate,
crankcount: cranks,
cranktime: cranksCurrentEventTime
};
// ensure value of cranks is in the range specified by the BLE specification
cranks = cranks % 65535;
cranksLastEventTime = cranksCurrentEventTime;
// Reset the fill-data timer if it is set
if (fillInTimer) {
clearTimeout(fillInTimer);
fillInTimer = null;
}
// Pass data to services/characteritcs to process and send to client; set a timer for fill-data
if (connectedCount > 0) {
keiserBLE.notifyClient(dataToSend);
fillInTimer = setTimeout(sendFillInData, 1000);
}
}
}
catch (err) {
console.log(`\tError parsing: ${err}`);
console.log(`\t ${err.stack}`);
}
}
});