Skip to content

Instantly share code, notes, and snippets.

@xmlking
Last active November 6, 2020 12:28
Show Gist options
  • Save xmlking/86fea17b3cb8042464892c75f45cfd22 to your computer and use it in GitHub Desktop.
Save xmlking/86fea17b3cb8042464892c75f45cfd22 to your computer and use it in GitHub Desktop.
web-bluetooth demo with Polar H7 Heart Rate Monitor *** need Chrome v54 ***
<html>
<head>
<link rel="stylesheet" type="text/css" href="styles.css">
<script src="script.js"></script>
</head>
<body>
<div class='hr-table'>
<div class='hr-row'>
<div class='hr-cell'>
<div class='hr-header'>Heart Rate:</div>
<div class='hr-value' id='hr'>0</div>
</div>
<div class='hr-cell'>
<div class='hr-header'>Average:</div>
<div class='hr-value' id='avg'>0.0</div>
</div>
</div>
</div>
<form><button>Start</button></form>
<script>
document.querySelector('form').addEventListener('submit', function(event) {
event.stopPropagation();
event.preventDefault();
let hrm = new HeartRateMonitor();
hrm.start();
});
</script>
</body>
</html>
class HeartRateMonitor {
constructor() {
this.SERVICE_ID = 0x180D;
this.CHARACTERISTIC_ID = 0x2A37;
this.hrElement_ = document.getElementById('hr');
this.avgElement_ = document.getElementById('avg');
this.resetAverage_();
}
computeAverage_() {
if (this.timeSum_ > 0) {
let avg = this.hrSum_ / ((this.timeSum_) * 2);
return avg.toFixed(1);
}
return '0.0';
}
resetAverage_() {
this.lastTick_ = 0;
this.lastHr_ = 0;
this.hrSum_ = 0;
this.timeSum_ = 0;
}
parseHeartRate_(data) {
let flags = data.getUint8(0);
if (flags & 0x1) {
return data.getUint16(1, true);
}
return data.getUint8(1);
}
onHeartRateChanged_(event) {
console.log(event);
let dataView = event.target.value;
let tick = (new Date()).getTime();
let hr = this.parseHeartRate_(dataView);
// Ignore readings where the HR or last HR value is 0 - treat this as a
// failed reading from the sensor.
if (this.lastTick_ && hr && this.lastHr_) {
this.hrSum_ += (tick - this.lastTick_) * (hr + this.lastHr_);
this.timeSum_ += tick - this.lastTick_;
}
this.lastTick_ = tick;
this.lastHr_ = hr;
this.hrElement_.textContent = hr;
this.avgElement_.textContent = this.computeAverage_();
}
handleCharacteristic_(characteristic) {
characteristic.addEventListener('characteristicvaluechanged',
event => this.onHeartRateChanged_(event));
return characteristic.startNotifications();
}
start() {
this.resetAverage_();
let options = {filters: [{
services: [this.SERVICE_ID],
namePrefix: 'Polar H7'
}]};
navigator.bluetooth.requestDevice(options)
.then(device => {
return device.gatt.connect();
})
.then(server => {
return server.getPrimaryService(this.SERVICE_ID);
})
.then(service => {
return service.getCharacteristic(this.CHARACTERISTIC_ID);
})
.then(characteristic => this.handleCharacteristic_(characteristic))
.catch(error => {
console.log('Error: ' + error);
});
}
}
body {
background-color: black;
color: gray;
}
.hr-cell {
display: table-cell;
text-align: center;
width: 50%;
height: 100%;
vertical-align: middle;
}
.hr-header {
font-size: 1.5em;;
}
.hr-value {
font-size: 3.0em;
}
.hr-row {
font-family: "Roboto";
display: table-row;
}
.hr-table {
height: 90%;
width: 100%;
display: table;
}
button {
padding: 8px 0px 8px 0px;
margin: 6px 0px 6px 0px;
min-width: 88px;
font-size: 18px;
text-align: center;
text-transform: uppercase;
text-decoration:none;
border: none;
outline: none;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment