From 82ea342d390a8715be68cd48560192d72888d6bd Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 24 Apr 2023 10:42:16 +0100 Subject: [PATCH] resurface original bthrm app as bthrmlite - for https://forum.espruino.com/conversations/385841/#comment16951663 --- apps/bthrmlite/ChangeLog | 1 + apps/bthrmlite/README.md | 42 +++++++++++++++++++++ apps/bthrmlite/app-icon.js | 1 + apps/bthrmlite/app.png | Bin 0 -> 2756 bytes apps/bthrmlite/boot.js | 71 +++++++++++++++++++++++++++++++++++ apps/bthrmlite/metadata.json | 15 ++++++++ 6 files changed, 130 insertions(+) create mode 100644 apps/bthrmlite/ChangeLog create mode 100644 apps/bthrmlite/README.md create mode 100644 apps/bthrmlite/app-icon.js create mode 100644 apps/bthrmlite/app.png create mode 100644 apps/bthrmlite/boot.js create mode 100644 apps/bthrmlite/metadata.json diff --git a/apps/bthrmlite/ChangeLog b/apps/bthrmlite/ChangeLog new file mode 100644 index 000000000..2286a7f70 --- /dev/null +++ b/apps/bthrmlite/ChangeLog @@ -0,0 +1 @@ +0.01: New App! \ No newline at end of file diff --git a/apps/bthrmlite/README.md b/apps/bthrmlite/README.md new file mode 100644 index 000000000..7dd1751a7 --- /dev/null +++ b/apps/bthrmlite/README.md @@ -0,0 +1,42 @@ +# Bluetooth Heart Rate Monitor - Lite + +When this app is installed it overrides Bangle.js's built in heart rate monitor with an external Bluetooth one. + +The [`bthrm` app](https://banglejs.com/apps/?id=bthrm) is a much more sophisticated version of this app, however is uses a lot more +RAM so may not be suitable for Bangle.js 1. + +HRM is requested it searches on Bluetooth for a heart rate monitor, connects, and sends data back using the `Bangle.on('HRM'` event as if it came from the on board monitor. + +This means it's compatible with many Bangle.js apps including: + +* [Heart Rate Widget](https://banglejs.com/apps/#widhrt) +* [Heart Rate Recorder](https://banglejs.com/apps/#heart) + +It it NOT COMPATIBLE with [Heart Rate Monitor](https://banglejs.com/apps/#hrm) +as that requires live sensor data (rather than just BPM readings). + +## Usage + +Just install the app, then install an app that uses the heart rate monitor. + +Once an app requests Heart Rate `bthrmlite` will automatically try and connect to the first bluetooth +heart rate monitor it finds. + +**To disable this and return to normal HRM, uninstall the app** + +## Compatible Heart Rate Monitors + +This works with any heart rate monitor providing the standard Bluetooth +Heart Rate Service (`180D`) and characteristic (`2A37`). + +So far it has been tested on: + +* CooSpo Bluetooth Heart Rate Monitor + +## Internals + +This replaces `Bangle.setHRMPower` with its own implementation. + +## Creator + +Gordon Williams \ No newline at end of file diff --git a/apps/bthrmlite/app-icon.js b/apps/bthrmlite/app-icon.js new file mode 100644 index 000000000..04a5ee610 --- /dev/null +++ b/apps/bthrmlite/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4UA///g3yy06AoIZNitUAg8AgtVqtQAgoRCAwITBAggABAoIABAgsAgIGDoIEDoApDAAwwBFIV1BYo1E+oLTAgQLGJon9BZNXBatdBYRVFBYN/r9fHoxTBBYYlEL4QLFq/a1WUgE///fr4xBv/+1Wq1EAh/3/tX6/fv/6BYOqwCzBBYf9tWq9QLF79X+oLBDIOgKgILEEIIxBGAMVNAP/BYf/BYUFBYJSB6wLC9QLBeAQLBqwLCGAL9BBYmr9X+GAILBbIIlBBYP6/wwBBYMFBYZGB/4XDGAILD34vEcwYLB15HBBYYkBBYWrFwILDKoRTCVIQLCEgQXIEgVaF44YCoRHHAAMUgQuBNgILFgECO4W/BZCPFBYinGBY6/CAArXFBY7vDAAsq1QuB0ALIOwOABY0KEgJGGGAguHDAYDBA==")) diff --git a/apps/bthrmlite/app.png b/apps/bthrmlite/app.png new file mode 100644 index 0000000000000000000000000000000000000000..40c2ab024622fd92cf3908991804eb1def70e7ac GIT binary patch literal 2756 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 KMNUMnLSTaZ|1XvR literal 0 HcmV?d00001 diff --git a/apps/bthrmlite/boot.js b/apps/bthrmlite/boot.js new file mode 100644 index 000000000..96996b0a7 --- /dev/null +++ b/apps/bthrmlite/boot.js @@ -0,0 +1,71 @@ +(function() { + var log = function() {};//print + var gatt; + + Bangle.setHRMPower = function(isOn, app) { + // Do app power handling + if (!app) app="?"; + log("setHRMPower ->", isOn, app); + if (Bangle._PWR===undefined) Bangle._PWR={}; + if (Bangle._PWR.HRM===undefined) Bangle._PWR.HRM=[]; + if (isOn && !Bangle._PWR.HRM.includes(app)) Bangle._PWR.HRM.push(app); + if (!isOn && Bangle._PWR.HRM.includes(app)) Bangle._PWR.HRM = Bangle._PWR.HRM.filter(a=>a!=app); + isOn = Bangle._PWR.HRM.length; + // so now we know if we're really on + if (isOn) { + log("setHRMPower on", app); + if (!gatt) { + log("HRM not already on"); + NRF.requestDevice({ filters: [{ services: ['180D'] }] }).then(function(device) { + log("Found device "+device.id); + device.on('gattserverdisconnected', function(reason) { + gatt = undefined; + }); + return device.gatt.connect(); + }).then(function(g) { + log("Connected"); + gatt = g; + return gatt.getPrimaryService(0x180D); + }).then(function(service) { + return service.getCharacteristic(0x2A37); + }).then(function(characteristic) { + log("Got characteristic"); + characteristic.on('characteristicvaluechanged', function(event) { + var dv = event.target.value; + var flags = dv.getUint8(0); + // 0 = 8 or 16 bit + // 1,2 = sensor contact + // 3 = energy expended shown + // 4 = RR interval + var bpm = (flags&1) ? (dv.getUint16(1)/100/* ? */) : dv.getUint8(1); // 8 or 16 bit + /* var idx = 2 + (flags&1); // index of next field + if (flags&8) idx += 2; // energy expended + if (flags&16) { + var interval = dv.getUint16(idx,1); // in milliseconds + }*/ + Bangle.emit('HRM',{ + bpm:bpm, + confidence:100 + }); + }); + return characteristic.startNotifications(); + }).then(function() { + log("Ready"); + console.log("Done!"); + }).catch(function(err) { + console.log("Error",err); + gatt = undefined; + }); + } + } else { // not on + log("setHRMPower off", app); + if (gatt) { + log("HRM connected - disconnecting"); + try {gatt.disconnect();}catch(e) { + log("HRM disconnect error", e); + } + gatt = undefined; + } + } + }; +})(); \ No newline at end of file diff --git a/apps/bthrmlite/metadata.json b/apps/bthrmlite/metadata.json new file mode 100644 index 000000000..e4b95cca8 --- /dev/null +++ b/apps/bthrmlite/metadata.json @@ -0,0 +1,15 @@ +{ "id": "bthrmlite", + "name": "Bluetooth Heart Rate Monitor (Lite)", + "shortName":"BT HRM", + "version":"0.01", + "description": "Overrides Bangle.js's build in heart rate monitor with an external Bluetooth one. Cut-down version that uses less RAM.", + "icon": "app.png", + "tags": "health,bluetooth", + "type": "bootloader", + "supports" : ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"bthrmlite.boot.js","url":"boot.js"}, + {"name":"bthrmlite.img","url":"app-icon.js","evaluate":true} + ] +} \ No newline at end of file