From 089f0cd4386c24a9d05fd9bd258ed436fd375253 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Thu, 6 Jan 2022 17:39:39 +0100 Subject: [PATCH 1/4] Emit additional BTHRM event and allow overwriting HRM optionally --- apps.json | 3 +- apps/bthrm/boot.js | 65 ++++++++++++++++++++++++++++++++---------- apps/bthrm/settings.js | 33 +++++++++++++++++++++ 3 files changed, 85 insertions(+), 16 deletions(-) create mode 100644 apps/bthrm/settings.js diff --git a/apps.json b/apps.json index 95c7b4bbc..6aa109142 100644 --- a/apps.json +++ b/apps.json @@ -1049,7 +1049,8 @@ "readme": "README.md", "storage": [ {"name":"bthrm.boot.js","url":"boot.js"}, - {"name":"bthrm.img","url":"app-icon.js","evaluate":true} + {"name":"bthrm.img","url":"app-icon.js","evaluate":true}, + {"name":"bthrm.settings.js","url":"settings.js"} ] }, { diff --git a/apps/bthrm/boot.js b/apps/bthrm/boot.js index 88e574480..0aa8d5c96 100644 --- a/apps/bthrm/boot.js +++ b/apps/bthrm/boot.js @@ -2,24 +2,43 @@ var log = function() {};//print var gatt; var status; - - Bangle.isHRMOn = function() { + + var origIsHRMOn = Bangle.isHRMOn; + + Bangle.isBTHRMOn = function(){ return (status=="searching" || status=="connecting") || (gatt!==undefined); } - Bangle.setHRMPower = function(isOn, app) { + + Bangle.isHRMOn = function() { + var settings = require('Storage').readJSON("bthrm.json", true) || {}; + + print(settings); + if (settings.enabled && !settings.replace){ + return origIsHRMOn(); + } else if (settings.enabled && settings.replace){ + return Bangle.isBTHRMOn(); + } + return origIsHRMOn() || Bangle.isBTHRMOn(); + } + + Bangle.setBTHRMPower = function(isOn, app) { + + + var settings = require('Storage').readJSON("bthrm.json", true) || {}; + // Do app power handling if (!app) app="?"; - log("setHRMPower ->", isOn, app); + log("setBTHRMPower ->", 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; + if (Bangle._PWR.BTHRM===undefined) Bangle._PWR.BTHRM=[]; + if (isOn && !Bangle._PWR.BTHRM.includes(app)) Bangle._PWR.BTHRM.push(app); + if (!isOn && Bangle._PWR.BTHRM.includes(app)) Bangle._PWR.BTHRM = Bangle._PWR.BTHRM.filter(a=>a!=app); + isOn = Bangle._PWR.BTHRM.length; // so now we know if we're really on if (isOn) { - log("setHRMPower on", app); - if (!Bangle.isHRMOn()) { - log("HRM not already on"); + log("setBTHRMPower on", app); + if (!Bangle.isBTHRMOn()) { + log("BTHRM not already on"); status = "searching"; NRF.requestDevice({ filters: [{ services: ['180D'] }] }).then(function(device) { log("Found device "+device.id); @@ -49,7 +68,11 @@ if (flags&16) { var interval = dv.getUint16(idx,1); // in milliseconds }*/ - Bangle.emit('HRM',{ + + + var eventName = settings.replace ? "HRM" : "BTHRM"; + + Bangle.emit(eventName, { bpm:bpm, confidence:100 }); @@ -65,15 +88,27 @@ }); } } else { // not on - log("setHRMPower off", app); + log("setBTHRMPower off", app); if (gatt) { - log("HRM connected - disconnecting"); + log("BTHRM connected - disconnecting"); status = undefined; try {gatt.disconnect();}catch(e) { - log("HRM disconnect error", e); + log("BTHRM disconnect error", e); } gatt = undefined; } } }; + + var origSetHRMPower = Bangle.setHRMPower; + + Bangle.setHRMPower = function(isOn, app) { + var settings = require('Storage').readJSON("bthrm.json", true) || {}; + if (settings.enabled || !isOn){ + Bangle.setBTHRMPower(isOn, app); + } + if (settings.enabled && !settings.replace || !isOn){ + origSetHRMPower(isOn, app); + } + } })(); diff --git a/apps/bthrm/settings.js b/apps/bthrm/settings.js new file mode 100644 index 000000000..8cb00614e --- /dev/null +++ b/apps/bthrm/settings.js @@ -0,0 +1,33 @@ +(function(back) { + var FILE = "bthrm.json"; + + var settings = Object.assign({ + enabled: true, + replace: true, + }, require('Storage').readJSON(FILE, true) || {}); + + function writeSettings() { + require('Storage').writeJSON(FILE, settings); + } + + E.showMenu({ + '': { 'title': 'Bluetooth HRM' }, + '< Back': back, + 'Use BT HRM': { + value: !!settings.enabled, + format: v => settings.enabled ? "On" : "Off", + onchange: v => { + settings.enabled = v; + writeSettings(); + } + }, + 'Use HRM event': { + value: !!settings.replace, + format: v => settings.replace ? "On" : "Off", + onchange: v => { + settings.replace = v; + writeSettings(); + } + } + }); +}) From 55c7ed5dd8b7273baae42606e66b926126592ebd Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Thu, 6 Jan 2022 17:41:26 +0100 Subject: [PATCH 2/4] Adds app to check status of BT/HRM --- apps.json | 3 ++- apps/bthrm/bthrm.js | 61 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 apps/bthrm/bthrm.js diff --git a/apps.json b/apps.json index 6aa109142..c3001a31d 100644 --- a/apps.json +++ b/apps.json @@ -1043,11 +1043,12 @@ "version": "0.01", "description": "Overrides Bangle.js's build in heart rate monitor with an external Bluetooth one.", "icon": "app.png", - "type": "boot", + "type": "app", "tags": "health,bluetooth", "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "storage": [ + {"name":"bthrm.app.js","url":"bthrm.js"}, {"name":"bthrm.boot.js","url":"boot.js"}, {"name":"bthrm.img","url":"app-icon.js","evaluate":true}, {"name":"bthrm.settings.js","url":"settings.js"} diff --git a/apps/bthrm/bthrm.js b/apps/bthrm/bthrm.js new file mode 100644 index 000000000..7c80c735f --- /dev/null +++ b/apps/bthrm/bthrm.js @@ -0,0 +1,61 @@ +var btm = g.getHeight()-1; +var eventInt = null; +var eventBt = null; +var counterInt = 0; +var counterBt = 0; + + +function draw(y, event, type, counter) { + var px = g.getWidth()/2; + g.reset(); + g.setFontAlign(0,0); + g.clearRect(0,y,g.getWidth(),y+80); + if (type == null || event == null || counter == 0) return; + var str = event.bpm + ""; + g.setFontVector(40).drawString(str,px,y+20); + str = "Confidence: " + event.confidence; + g.setFontVector(12).drawString(str,px,y+50); + str = "Event: " + type; + g.setFontVector(12).drawString(str,px,y+60); +} + +function onBtHrm(e) { + print("Event for BT " + JSON.stringify(e)); + counterBt += 5; + eventBt = e; +} + +function onHrm(e) { + print("Event for Int " + JSON.stringify(e)); + counterInt += 5; + eventInt = e; +} + +Bangle.on('BTHRM', onBtHrm); +Bangle.on('HRM', onHrm); + +Bangle.setHRMPower(1,'bthrm') +Bangle.setBTHRMPower(1,'bthrm') + +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +g.reset().setFont("6x8",2).setFontAlign(0,0); +g.drawString("Please wait...",g.getWidth()/2,g.getHeight()/2 - 16); + +function drawInt(){ + counterInt--; + if (counterInt < 0) counterInt = 0; + if (counterInt > 5) counterInt = 5; + draw(24, eventInt, "HRM", counterInt); +} +function drawBt(){ + counterBt--; + if (counterBt < 0) counterBt = 0; + if (counterBt > 5) counterBt = 5; + draw(100, eventBt, "BTHRM", counterBt); +} + +var interval = setInterval(drawInt, 1000); +var interval = setInterval(drawBt, 1000); From 3baf11613b242807dcdd9060eab60b1e9ddf4645 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Thu, 6 Jan 2022 17:42:29 +0100 Subject: [PATCH 3/4] Adds recorder app plugin to record the BTHRM event --- apps.json | 1 + apps/bthrm/recorder.js | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 apps/bthrm/recorder.js diff --git a/apps.json b/apps.json index c3001a31d..7c9cbffdd 100644 --- a/apps.json +++ b/apps.json @@ -1049,6 +1049,7 @@ "readme": "README.md", "storage": [ {"name":"bthrm.app.js","url":"bthrm.js"}, + {"name":"bthrm.recorder.js","url":"recorder.js"}, {"name":"bthrm.boot.js","url":"boot.js"}, {"name":"bthrm.img","url":"app-icon.js","evaluate":true}, {"name":"bthrm.settings.js","url":"settings.js"} diff --git a/apps/bthrm/recorder.js b/apps/bthrm/recorder.js new file mode 100644 index 000000000..40f64a676 --- /dev/null +++ b/apps/bthrm/recorder.js @@ -0,0 +1,27 @@ +(function(recorders) { + recorders.bthrm = function() { + var bpm = 0; + function onHRM(h) { + bpm = h.bpm; + } + return { + name : "BTHR", + fields : ["BT Heartrate"], + getValues : () => { + result = [bpm]; + bpm = 0; + return result; + }, + start : () => { + Bangle.on('BTHRM', onHRM); + Bangle.setBTHRMPower(1,"recorder"); + }, + stop : () => { + Bangle.removeListener('BTHRM', onHRM); + Bangle.setBTHRMPower(0,"recorder"); + }, + draw : (x,y) => g.setColor(Bangle.isBTHRMOn()?"#00f":"#88f").drawImage(atob("DAwBAAAAMMeef+f+f+P8H4DwBgAA"),x,y) + }; + } +}) + From 01d236b761c61819aa16d5fa75dd55877dd9289a Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Thu, 6 Jan 2022 17:44:44 +0100 Subject: [PATCH 4/4] Bump version and changelog --- apps.json | 2 +- apps/bthrm/ChangeLog | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 7c9cbffdd..3601aeca4 100644 --- a/apps.json +++ b/apps.json @@ -1040,7 +1040,7 @@ "id": "bthrm", "name": "Bluetooth Heart Rate Monitor", "shortName": "BT HRM", - "version": "0.01", + "version": "0.02", "description": "Overrides Bangle.js's build in heart rate monitor with an external Bluetooth one.", "icon": "app.png", "type": "app", diff --git a/apps/bthrm/ChangeLog b/apps/bthrm/ChangeLog index 5560f00bc..27a58dd78 100644 --- a/apps/bthrm/ChangeLog +++ b/apps/bthrm/ChangeLog @@ -1 +1,4 @@ 0.01: New App! +0.02: Make overriding the HRM event optional + Emit BTHRM event for external sensor + Add recorder app plugin