-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
122 lines (96 loc) · 4.32 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
var noble = require('noble');
const WebSocket = require('ws');
var express = require('express');
var path = require('path');
var app = express();
var server = require('http').createServer();
// Use a dictionary for the peripherals. Key is the mac address and value is the noble peripheral object
let devices = {};
app.use(express.static(path.join(__dirname, '/public')));
const wss = new WebSocket.Server({server: server});
wss.on('connection', function (ws) {
initBluetooth(ws);
ws.on('close', function () {
console.log('stopping client interval');
});
});
server.on('request', app);
server.listen(8080, function () {
console.log('Listening on http://localhost:8080');
});
function initBluetooth(ws) {
noble.startScanning(["180d"]);
noble.on('stateChange', function (state) {
if (state === 'poweredOn') {
// Seek for peripherals broadcasting the heart rate service
// This will pick up a Polar H7 and should pick up other ble heart rate bands
// Will use whichever the first one discovered is if more than one are in range
noble.startScanning(["180d"]);
} else {
noble.stopScanning();
}
});
noble.on('scanStart', function () {
console.log('Scanning for peripherals ...');
});
noble.on('scanStop', function () {
console.log('Scan stopped.');
setTimeout(function () {
noble.startScanning(["180d"]);
}, 500);
});
noble.on('discover', function (peripheral) {
console.log('Found peripheral.');
peripheral.connect(function (err) {
handleConnect(err, peripheral);
});
});
function handleConnect(err, peripheral) {
console.log('Connected.');
let address = peripheral.address.replace(/\:/g, "");
devices[address] = peripheral;
var serviceUUID = ["180d"];
// 2a37 is the characteristic for heart rate measurement
// https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
var characteristicUUID = ["2a37"];
// use noble's discoverSomeServicesAndCharacteristics
// scoped to the heart rate service and measurement characteristic
devices[address].discoverSomeServicesAndCharacteristics(serviceUUID, characteristicUUID, function (error, services, characteristics) {
if (!devices[characteristics[0]._peripheralId]) {
console.log('not connected yet');
} else {
devices[characteristics[0]._peripheralId].characteristics = characteristics;
characteristics[0].notify(true, function (error) {
characteristics[0].on('data', function (data, isNotification) {
// Upon receiving data, output the BPM
// The actual BPM data is stored in the 2nd bit in data (at array index 1)
// Thanks Steve Daniel: http://www.raywenderlich.com/52080/introduction-core-bluetooth-building-heart-rate-monitor
// Measurement docs here: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
devices[characteristics[0]._peripheralId].heartRate = data[1];
const result = Object.keys(devices).map((key) => {
return {
name: devices[key].advertisement.localName,
heartRate: devices[key].heartRate,
}
})
ws.send(JSON.stringify(result), function () { /* ignore errors */
});
});
})
}
});
peripheral.once('disconnect', function () {
handleDisconnect(peripheral);
});
}
function handleDisconnect(peripheral) {
console.log('Connection lost.');
let address = peripheral.address.replace(/\:/g, "");
if (devices[address].characteristics) {
devices[address].characteristics[0].unsubscribe(function () {
console.log('unsubscribed');
});
}
noble.stopScanning();
}
}