forked from FOSS/BangleApps
commit
d7756ee175
|
@ -0,0 +1,3 @@
|
|||
0.01: New App!
|
||||
0.02: Fixes
|
||||
0.03: updated to work with new API and additional features added such as longer recording time and additional filtered data
|
|
@ -3,11 +3,11 @@ Extract hrm raw signal data to CSV file
|
|||
|
||||
Simple app that will run the heart rate monitor for a defined period of time you set at the start.
|
||||
|
||||
-The app creates a csv file (it's actually just 1 column) and you can download this via My Apps in the App Loader.
|
||||
Updated to work with new API. Additional capability includes:
|
||||
|
||||
-The max time value is 60 minutes.
|
||||
|
||||
-The first item holds the data/time when the readings were taken and the file is reset each time the app is run.
|
||||
1. Now also records upto 2 hours - if you cancel at any time the CSV file will still be there, the timer you set at the start is more so that you get an alert when it's complete.
|
||||
2. Along with raw PPG readings, it also records bandpassed filtered data in a second column, available in the new API.
|
||||
3. Rather than overwriting 1 data file, the app will record upto 5 files before recording to a generic data file as a fallback if all 5 allocated files remain on the watch storage. The limit is in place to avoid going over storage limits as these files can get large over time.
|
||||
|
||||
-The hrm sensor is sampled @50Hz and this app does not do any processing on it other than clip overly high/extreme values, the array is written as-is. There is an example Python script that can process this signal, smooth it and also extract a myriad of heart rate variability metrics using the hrvanalysis library:
|
||||
https://github.com/jabituyaben/BangleJS-HRM-Signal-Processing
|
||||
|
|
|
@ -1,12 +1,25 @@
|
|||
var counter = 1;
|
||||
var counter = 15;
|
||||
var logging_started;
|
||||
var interval;
|
||||
var value;
|
||||
var filt;
|
||||
|
||||
var file = require("Storage").open("hrm_log.csv", "w");
|
||||
file.write("");
|
||||
var fileClosed = 0;
|
||||
var Storage = require("Storage");
|
||||
var file;
|
||||
|
||||
file = require("Storage").open("hrm_log.csv", "a");
|
||||
function exists(name){
|
||||
s = require('Storage');
|
||||
var fileList = s.list();
|
||||
var fileExists = false;
|
||||
for (let i = 0; i < fileList.length; i++) {
|
||||
fileExists = fileList[i].includes(name);
|
||||
if(fileExists){
|
||||
break;
|
||||
}
|
||||
}
|
||||
return fileExists;
|
||||
}
|
||||
|
||||
function update_timer() {
|
||||
g.clear();
|
||||
|
@ -33,47 +46,75 @@ function update_timer() {
|
|||
|
||||
function btn1Pressed() {
|
||||
if (!logging_started) {
|
||||
if (counter < 60)
|
||||
counter += 1;
|
||||
if (counter < 120)
|
||||
counter += 15;
|
||||
else
|
||||
counter = 1;
|
||||
counter = 15;
|
||||
update_timer();
|
||||
}
|
||||
}
|
||||
|
||||
function btn3Pressed() {
|
||||
if (!logging_started) {
|
||||
if (counter > 1)
|
||||
counter -= 1;
|
||||
if (counter > 15)
|
||||
counter -= 15;
|
||||
else
|
||||
counter = 60;
|
||||
counter = 120;
|
||||
update_timer();
|
||||
}
|
||||
}
|
||||
|
||||
function btn2Pressed() {
|
||||
launchtime = 0 | getTime();
|
||||
file.write(launchtime + "," + "\n");
|
||||
logging_started = true;
|
||||
counter = counter * 60;
|
||||
interval = setInterval(countDown, 1000);
|
||||
Bangle.setHRMPower(1);
|
||||
if (!logging_started) {
|
||||
var filename = "";
|
||||
var fileset = false;
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
filename = "HRM_data" + i.toString() + ".csv";
|
||||
if(exists(filename) == 0){
|
||||
file = require("Storage").open(filename,"w");
|
||||
console.log("creating new file " + filename);
|
||||
fileset = true;
|
||||
}
|
||||
if(fileset){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fileset){
|
||||
console.log("overwiting file");
|
||||
file = require("Storage").open("HRM_data.csv","w");
|
||||
}
|
||||
|
||||
file.write("");
|
||||
file = require("Storage").open(filename,"a");
|
||||
|
||||
//launchtime = 0 | getTime();
|
||||
//file.write(launchtime + "," + "\n");
|
||||
logging_started = true;
|
||||
counter = counter * 60;
|
||||
interval = setInterval(countDown, 1000);
|
||||
Bangle.setHRMPower(1);
|
||||
}
|
||||
}
|
||||
|
||||
function fmtMSS(e) {
|
||||
var m = Math.floor(e % 3600 / 60).toString().padStart(2, '0'),
|
||||
s = Math.floor(e % 60).toString().padStart(2, '0');
|
||||
return m + ':' + s;
|
||||
h = Math.floor(e / 3600);
|
||||
e %= 3600;
|
||||
m = Math.floor(e / 60);
|
||||
s = e % 60;
|
||||
return h + ":" + m + ':' + s;
|
||||
}
|
||||
|
||||
function countDown() {
|
||||
g.clear();
|
||||
counter--;
|
||||
if (counter == 0) {
|
||||
if (counter <= 0 && fileClosed == 0) {
|
||||
Bangle.setHRMPower(0);
|
||||
clearInterval(interval);
|
||||
g.drawString("Finished", g.getWidth() / 2, g.getHeight() / 2);
|
||||
Bangle.buzz(500, 1);
|
||||
fileClosed = 1;
|
||||
}
|
||||
else
|
||||
g.drawString(fmtMSS(counter), g.getWidth() / 2, g.getHeight() / 2);
|
||||
|
@ -85,13 +126,8 @@ setWatch(btn1Pressed, BTN1, { repeat: true });
|
|||
setWatch(btn2Pressed, BTN2, { repeat: true });
|
||||
setWatch(btn3Pressed, BTN3, { repeat: true });
|
||||
|
||||
Bangle.on('HRM', function (hrm) {
|
||||
for (let i = 0; i < hrm.raw.length; i++) {
|
||||
value = hrm.raw[i];
|
||||
if (value < -2)
|
||||
value = -2;
|
||||
if (value > 6)
|
||||
value = 6;
|
||||
file.write(value + "," + "\n");
|
||||
}
|
||||
Bangle.on('HRM-raw', function (hrm) {
|
||||
value = hrm.raw;
|
||||
filt = hrm.filt;
|
||||
file.write(value + "," + filt + "," + "\n");
|
||||
});
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "hrrawexp",
|
||||
"name": "HRM Data Exporter",
|
||||
"shortName": "HRM Data Exporter",
|
||||
"version": "0.01",
|
||||
"version": "0.03",
|
||||
"description": "export raw hrm signal data to a csv file",
|
||||
"icon": "app-icon.png",
|
||||
"tags": "",
|
||||
|
|
Loading…
Reference in New Issue