testing/converting heart rate apps for Bangle.js 2

pull/854/head
Gordon Williams 2021-10-21 12:40:34 +01:00
parent 38ab8521d1
commit 852f911dcf
10 changed files with 69 additions and 75 deletions

View File

@ -624,11 +624,11 @@
{ {
"id": "heart", "id": "heart",
"name": "Heart Rate Recorder", "name": "Heart Rate Recorder",
"version": "0.06", "version": "0.07",
"description": "Application that allows you to record your heart rate. Can run in background", "description": "Application that allows you to record your heart rate. Can run in background",
"icon": "app.png", "icon": "app.png",
"tags": "tool,health,widget", "tags": "tool,health,widget",
"supports": ["BANGLEJS"], "supports": ["BANGLEJS","BANGLEJS2"],
"interface": "interface.html", "interface": "interface.html",
"storage": [ "storage": [
{"name":"heart.app.js","url":"app.js"}, {"name":"heart.app.js","url":"app.js"},
@ -818,11 +818,11 @@
{ {
"id": "hrm", "id": "hrm",
"name": "Heart Rate Monitor", "name": "Heart Rate Monitor",
"version": "0.05", "version": "0.06",
"description": "Measure your heart rate and see live sensor data", "description": "Measure your heart rate and see live sensor data",
"icon": "heartrate.png", "icon": "heartrate.png",
"tags": "health", "tags": "health",
"supports": ["BANGLEJS"], "supports": ["BANGLEJS","BANGLEJS2"],
"storage": [ "storage": [
{"name":"hrm.app.js","url":"heartrate.js"}, {"name":"hrm.app.js","url":"heartrate.js"},
{"name":"hrm.img","url":"heartrate-icon.js","evaluate":true} {"name":"hrm.img","url":"heartrate-icon.js","evaluate":true}
@ -831,12 +831,12 @@
{ {
"id": "widhrm", "id": "widhrm",
"name": "Simple Heart Rate widget", "name": "Simple Heart Rate widget",
"version": "0.04", "version": "0.05",
"description": "When the screen is on, the widget turns on the heart rate monitor and displays the current heart rate (or last known in grey). For this to work well you'll need at least a 15 second LCD Timeout.", "description": "When the screen is on, the widget turns on the heart rate monitor and displays the current heart rate (or last known in grey). For this to work well you'll need at least a 15 second LCD Timeout.",
"icon": "widget.png", "icon": "widget.png",
"type": "widget", "type": "widget",
"tags": "health,widget", "tags": "health,widget",
"supports": ["BANGLEJS"], "supports": ["BANGLEJS","BANGLEJS2"],
"storage": [ "storage": [
{"name":"widhrm.wid.js","url":"widget.js"} {"name":"widhrm.wid.js","url":"widget.js"}
] ]
@ -3334,12 +3334,12 @@
{ {
"id": "widhrt", "id": "widhrt",
"name": "HRM Widget", "name": "HRM Widget",
"version": "0.02", "version": "0.03",
"description": "Tiny widget to show the power on/off status of the Heart Rate Monitor. Requires firmware v2.08.167 or later", "description": "Tiny widget to show the power on/off status of the Heart Rate Monitor. Requires firmware v2.08.167 or later",
"icon": "widget.png", "icon": "widget.png",
"type": "widget", "type": "widget",
"tags": "widget,hrm", "tags": "widget,hrm",
"supports": ["BANGLEJS"], "supports": ["BANGLEJS","BANGLEJS2"],
"readme": "README.md", "readme": "README.md",
"storage": [ "storage": [
{"name":"widhrt.wid.js","url":"widget.js"} {"name":"widhrt.wid.js","url":"widget.js"}

View File

@ -12,3 +12,4 @@
Generate scale based on defined minimum and maximum measurement Generate scale based on defined minimum and maximum measurement
Added background line on 50% to ease estimation of drawn values Added background line on 50% to ease estimation of drawn values
0.06: tag HRM power requests to allow this ot work alongside other widgets/apps (fix #799) 0.06: tag HRM power requests to allow this ot work alongside other widgets/apps (fix #799)
0.07: theme support

View File

@ -221,9 +221,9 @@ function graphRecord(n) {
if (tempCount == startLine) { if (tempCount == startLine) {
// generating rgaph in loop when reaching startLine to keep loading // generating rgaph in loop when reaching startLine to keep loading
// message on screen until graph can be drawn // message on screen until graph can be drawn
g.clear(). g.reset().clearRect(0,24,g.getWidth(),g.getHeight()).
// Home for Btn2 // Home for Btn2
setColor(1, 1, 1). setColor(g.theme.fg).
drawLine(220, 118, 227, 110). drawLine(220, 118, 227, 110).
drawLine(227, 110, 234, 118). drawLine(227, 110, 234, 118).
drawPoly([222,117,222,125,232,125,232,117], false). drawPoly([222,117,222,125,232,125,232,117], false).
@ -245,7 +245,7 @@ function graphRecord(n) {
// scale indicator line for 50% // scale indicator line for 50%
drawLine(GraphXZero - GraphMarkerOffset, GraphY100 + (GraphYZero - GraphY100)/2, GraphXZero, GraphY100 + (GraphYZero - GraphY100)/2). drawLine(GraphXZero - GraphMarkerOffset, GraphY100 + (GraphYZero - GraphY100)/2, GraphXZero, GraphY100 + (GraphYZero - GraphY100)/2).
// background line for 50% // background line for 50%
setColor(1, 1, 1). setColor(g.theme.fg).
drawLine(GraphXZero + 1, GraphY100 + (GraphYZero - GraphY100)/2, GraphXMax, GraphY100 + (GraphYZero - GraphY100)/2). drawLine(GraphXZero + 1, GraphY100 + (GraphYZero - GraphY100)/2, GraphXMax, GraphY100 + (GraphYZero - GraphY100)/2).
setFontAlign(1, -1, 0). setFontAlign(1, -1, 0).
setFont("Vector", 10); setFont("Vector", 10);

View File

@ -3,3 +3,4 @@
0.03: Fix timing issues, and use 1/2 scale to keep graph on screen 0.03: Fix timing issues, and use 1/2 scale to keep graph on screen
0.04: Update for new firmwares that have a 'HRM-raw' event 0.04: Update for new firmwares that have a 'HRM-raw' event
0.05: Tweaks for 'HRM-raw' handling 0.05: Tweaks for 'HRM-raw' handling
0.06: Add widgets

View File

@ -1 +1 @@
require("heatshrink").decompress(atob("mEwghC/AH4AThnMAAXABJoMHBwgJJAAYMFAAIJLFxImCBJIuLABYuI4gXNNZFCC6AIFkZIQA4szC6vEmdMC60sC6nDmc8C6RDBC4irLC4gTBocymgGBoYXO4UyUwNEAYKrMC4ZEBUwNMVAR7LC4dDCoYBBSYJ7DoZQCC4kCmczkc0JIVM4UzmgaBAAQWD4AXBggJBJAIkBocs4c0BAQXJJARBD4c8oc8HAKZCI4gWCVAYXEJIJoCOovNC4cMUIQPB4RFBTAYAFIwapEC4JyCZAalHGAvCJYZYCVAYuIMIhjE5heGCwxhDMYTtIFw4wFoYsGFxIwF4YuRGAh7DFxxhGFyIYKCxqrGIpwwKFx4YGCyJJFCyQYDCygA/AH4AFA=")) require("heatshrink").decompress(atob("mEw4UA///g3yrv/7f+Jf4AJgNVoAEGAANVAAIEGCIQABoAEEBYMFAwVQAggLBioGCqgEEFIgAGFwdXBYw1Dr4LKrwLHIIVaBYxNDvXVBanVteVBZGVt+VKooLBq+19u1JItQgNW0vlBYIxEL4Ne1u18taGIN9BYUD1XvBYN62+q1a0D1d7ytttYLEWYV6BYNt93VEYKzCita6t59vqX4sFIgN70tqa4pUBTgO1vbvFgB0BKQNZawYACdYNeytdFwgwCBYJ2DFwQwCqoxBFwwABBYoKEGAKyDFwgwDFw4kDERBVDEQ4kEEQ4kDBRAYBERBuCNAoA/AA4="))

View File

@ -4,13 +4,14 @@ Bangle.setHRMPower(1);
var hrmInfo, hrmOffset = 0; var hrmInfo, hrmOffset = 0;
var hrmInterval; var hrmInterval;
var btm = g.getHeight()-1; var btm = g.getHeight()-1;
var lastHrmPt = []; // last xy coords we draw a line to
function onHRM(h) { function onHRM(h) {
if (counter!==undefined) { if (counter!==undefined) {
// the first time we're called remove // the first time we're called remove
// the countdown // the countdown
counter = undefined; counter = undefined;
g.clear(); g.clearRect(0,24,g.getWidth(),g.getHeight());
} }
hrmInfo = h; hrmInfo = h;
/* On 2v09 and earlier firmwares the only solution for realtime /* On 2v09 and earlier firmwares the only solution for realtime
@ -28,7 +29,7 @@ function onHRM(h) {
var px = g.getWidth()/2; var px = g.getWidth()/2;
g.setFontAlign(0,0); g.setFontAlign(0,0);
g.clearRect(0,24,239,80); g.clearRect(0,24,g.getWidth(),80);
g.setFont("6x8").drawString("Confidence "+hrmInfo.confidence+"%", px, 75); g.setFont("6x8").drawString("Confidence "+hrmInfo.confidence+"%", px, 75);
var str = hrmInfo.bpm; var str = hrmInfo.bpm;
g.setFontVector(40).drawString(str,px,45); g.setFontVector(40).drawString(str,px,45);
@ -43,17 +44,18 @@ Bangle.on('HRM-raw', function(v) {
hrmOffset++; hrmOffset++;
if (hrmOffset>g.getWidth()) { if (hrmOffset>g.getWidth()) {
hrmOffset=0; hrmOffset=0;
g.clearRect(0,80,239,239); g.clearRect(0,80,g.getWidth(),g.getHeight());
g.moveTo(-100,0); lastHrmPt = [-100,0];
} }
y = E.clip(btm-v.filt/4,btm-10,btm); y = E.clip(btm-v.filt/4,btm-10,btm);
g.setColor(1,0,0).fillRect(hrmOffset,btm, hrmOffset, y); g.setColor(1,0,0).fillRect(hrmOffset,btm, hrmOffset, y);
y = E.clip(170 - (v.raw/2),80,btm); y = E.clip(170 - (v.raw/2),80,btm);
g.setColor(g.theme.fg).lineTo(hrmOffset, y); g.setColor(g.theme.fg).drawLine(lastHrmPt[0],lastHrmPt[1],hrmOffset, y);
lastHrmPt = [hrmOffset, y];
if (counter !==undefined) { if (counter !==undefined) {
counter = undefined; counter = undefined;
g.clear(); g.clearRect(0,24,g.getWidth(),g.getHeight());
} }
}); });
@ -65,7 +67,10 @@ function countDown() {
setTimeout(countDown, 1000); setTimeout(countDown, 1000);
} }
} }
g.clear().setFont("6x8",2).setFontAlign(0,0); 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); g.drawString("Please wait...",g.getWidth()/2,g.getHeight()/2 - 16);
countDown(); countDown();
@ -79,13 +84,14 @@ function readHRM() {
if (!hrmInfo) return; if (!hrmInfo) return;
if (hrmOffset==0) { if (hrmOffset==0) {
g.clearRect(0,100,239,239); g.clearRect(0,100,g.getWidth(),g.getHeight());
g.moveTo(-100,0); lastHrmPt = [-100,0];
} }
for (var i=0;i<2;i++) { for (var i=0;i<2;i++) {
var a = hrmInfo.raw[hrmOffset]; var a = hrmInfo.raw[hrmOffset];
hrmOffset++; hrmOffset++;
y = E.clip(170 - (a*2),100,230); y = E.clip(170 - (a*2),100,230);
g.setColor(g.theme.fg).lineTo(hrmOffset, y); g.setColor(g.theme.fg).drawLine(lastHrmPt[0],lastHrmPt[1],hrmOffset, y);
lastHrmPt = [hrmOffset, y];
} }
} }

View File

@ -2,3 +2,4 @@
0.02: Tweaks for variable size widget system 0.02: Tweaks for variable size widget system
0.03: Ensure redrawing works with variable size widget system 0.03: Ensure redrawing works with variable size widget system
0.04: tag HRM power requests to allow this ot work alongside other widgets/apps (fix #799) 0.04: tag HRM power requests to allow this ot work alongside other widgets/apps (fix #799)
0.05: Use new 'lock' event, not LCD (so it works on Bangle.js 2)

View File

@ -1,9 +1,28 @@
(() => { (() => {
var currentBPM = undefined; if (!Bangle.isLocked) return; // old firmware
var lastBPM = undefined; var currentBPM;
var firstBPM = true; // first reading since sensor turned on var lastBPM;
function draw() { // turn on sensor when the LCD is unlocked
Bangle.on('lock', function(isLocked) {
if (!isLocked) {
Bangle.setHRMPower(1,"widhrm");
currentBPM = undefined;
WIDGETS["hrm"].draw();
} else {
Bangle.setHRMPower(0,"widhrm");
}
});
Bangle.on('HRM',function(d) {
currentBPM = d.bpm;
lastBPM = currentBPM;
WIDGETS["hrm"].draw();
});
Bangle.setHRMPower(!Bangle.isLocked(),"widhrm");
// add your widget
WIDGETS["hrm"]={area:"tl",width:24,draw:function() {
var width = 24; var width = 24;
g.reset(); g.reset();
g.setFont("6x8", 1); g.setFont("6x8", 1);
@ -16,36 +35,10 @@
} }
if (bpm===undefined) if (bpm===undefined)
bpm = "--"; bpm = "--";
g.setColor(isCurrent ? "#ffffff" : "#808080"); g.setColor(isCurrent ? g.theme.fg : "#808080");
g.drawString(bpm, this.x+width/2, this.y+19); g.drawString(bpm, this.x+width/2, this.y+19);
g.setColor(isCurrent ? "#ff0033" : "#808080"); g.setColor(isCurrent ? "#ff0033" : "#808080");
g.drawImage(atob("CgoCAAABpaQ//9v//r//5//9L//A/+AC+AAFAA=="),this.x+(width-10)/2,this.y+1); g.drawImage(atob("CgoCAAABpaQ//9v//r//5//9L//A/+AC+AAFAA=="),this.x+(width-10)/2,this.y+1);
g.setColor(-1); g.setColor(-1);
} }};
// redraw when the LCD turns on
Bangle.on('lcdPower', function(on) {
if (on) {
Bangle.setHRMPower(1,"widhrm");
firstBPM = true;
currentBPM = undefined;
WIDGETS["hrm"].draw();
} else {
Bangle.setHRMPower(0,"widhrm");
}
});
Bangle.on('HRM',function(d) {
if (firstBPM)
firstBPM=false; // ignore the first one as it's usually rubbish
else {
currentBPM = d.bpm;
lastBPM = currentBPM;
}
WIDGETS["hrm"].draw();
});
Bangle.setHRMPower(Bangle.isLCDOn(),"widhrm");
// add your widget
WIDGETS["hrm"]={area:"tl",width:24,draw:draw};
})(); })();

View File

@ -1,3 +1,5 @@
0.01: First version 0.01: First version
0.02: Don't break if running on 2v08 firmware (just don't display anything) 0.02: Don't break if running on 2v08 firmware (just don't display anything)
0.03: Works with light theme
Doesn't drain battery by updating every 2 secs
fix alignment

View File

@ -1,28 +1,18 @@
(function(){ (function(){
if (!Bangle.isHRMOn) return; // old firmware if (!Bangle.isHRMOn) return; // old firmware
var hp = Bangle.setHRMPower;
Bangle.setHRMPower = () => {
hp.apply(Bangle, arguments);
WIDGETS.widhrt.draw();
};
function draw() { WIDGETS.widhrt={area:"tr",width:24,draw:function() {
g.reset(); g.reset();
if (Bangle.isHRMOn()) { if (Bangle.isHRMOn()) {
g.setColor(1,0,0); // on = red g.setColor("#f00"); // on = red
} else { } else {
g.setColor(0.3,0.3,0.3); // off = grey g.setColor(g.theme.dark ? "#333" : "#CCC"); // off = grey
} }
g.drawImage(atob("FhaBAAAAAAAAAAAAAcDgD8/AYeGDAwMMDAwwADDAAMOABwYAGAwAwBgGADAwAGGAAMwAAeAAAwAAAAAAAAAAAAA="), 10+this.x, 2+this.y); g.drawImage(atob("FhaBAAAAAAAAAAAAAcDgD8/AYeGDAwMMDAwwADDAAMOABwYAGAwAwBgGADAwAGGAAMwAAeAAAwAAAAAAAAAAAAA="), 1+this.x, 1+this.y);
} }};
var timerInterval;
Bangle.on('lcdPower', function(on) {
if (on) {
WIDGETS.widhrt.draw();
if (!timerInterval) timerInterval = setInterval(()=>WIDGETS["widhrt"].draw(), 2000);
} else {
if (timerInterval) {
clearInterval(timerInterval);
timerInterval = undefined;
}
}
});
WIDGETS.widhrt={area:"tr",width:24,draw:draw};
})(); })();