forked from FOSS/BangleApps
edited app.js
parent
3fb9e3fd50
commit
fb29c3d378
|
@ -1,8 +1,15 @@
|
||||||
let isMeasuring = false;
|
var isMeasuring = false;
|
||||||
let currentHeartRate = null;
|
var currentHeartRate = null;
|
||||||
let lcdTimeout;
|
var lcdTimeout;
|
||||||
let logData = [];
|
var bpmValues = [];
|
||||||
|
var logData = [];
|
||||||
|
var lastHeartRateLogTimestamp = 0;
|
||||||
|
|
||||||
|
// HRV calculation variables
|
||||||
|
var hrvSlots = [10, 20, 30, 60, 120, 300];
|
||||||
|
var hrvValues = {};
|
||||||
|
|
||||||
|
// Heart rate monitor functions
|
||||||
function startMeasure() {
|
function startMeasure() {
|
||||||
isMeasuring = true;
|
isMeasuring = true;
|
||||||
Bangle.setLCDTimeout(0);
|
Bangle.setLCDTimeout(0);
|
||||||
|
@ -13,7 +20,7 @@ function startMeasure() {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
Bangle.setHRMPower(1);
|
Bangle.setHRMPower(1);
|
||||||
Bangle.on('HRM', handleHeartRate);
|
Bangle.on('HRM', handleHeartRate);
|
||||||
Bangle.beep(400, 1000); // Buzz to indicate measurement start
|
Bangle.buzz(500, 20);
|
||||||
drawScreen();
|
drawScreen();
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
|
@ -24,25 +31,10 @@ function stopMeasure() {
|
||||||
Bangle.setLCDTimeout(10);
|
Bangle.setLCDTimeout(10);
|
||||||
Bangle.setHRMPower(0);
|
Bangle.setHRMPower(0);
|
||||||
Bangle.removeAllListeners('HRM');
|
Bangle.removeAllListeners('HRM');
|
||||||
saveDataToCSV(); // Save data to CSV when measurement stops
|
Bangle.buzz(500, 20);
|
||||||
Bangle.beep(400, 800); // Buzz to indicate measurement stop
|
|
||||||
drawScreen();
|
drawScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleHeartRate(hrm) {
|
|
||||||
if (hrm.confidence > 90) {
|
|
||||||
currentHeartRate = hrm.bpm;
|
|
||||||
let date = new Date();
|
|
||||||
let dateStr = require("locale").date(date);
|
|
||||||
let timeStr = require("locale").time(date, 1);
|
|
||||||
let seconds = date.getSeconds();
|
|
||||||
let timestamp = `${dateStr} ${timeStr}:${seconds}`; // Concatenate date, time, and seconds
|
|
||||||
logData.push({ timestamp: timestamp, heartRate: currentHeartRate });
|
|
||||||
drawScreen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function drawScreen(message) {
|
function drawScreen(message) {
|
||||||
g.clear(); // Clear the display
|
g.clear(); // Clear the display
|
||||||
|
|
||||||
|
@ -65,9 +57,9 @@ function drawScreen(message) {
|
||||||
g.setFont('6x8', 2);
|
g.setFont('6x8', 2);
|
||||||
g.drawString('Measuring...', g.getWidth() / 2, g.getHeight() / 2 - 10);
|
g.drawString('Measuring...', g.getWidth() / 2, g.getHeight() / 2 - 10);
|
||||||
|
|
||||||
// Draw current heart rate if available
|
// Draw current heart rate if available and not zero
|
||||||
|
if (currentHeartRate !== null && currentHeartRate > 0) {
|
||||||
g.setFont('6x8', 4);
|
g.setFont('6x8', 4);
|
||||||
if (currentHeartRate !== null) {
|
|
||||||
g.drawString(currentHeartRate.toString(), g.getWidth() / 2, g.getHeight() / 2 + 20);
|
g.drawString(currentHeartRate.toString(), g.getWidth() / 2, g.getHeight() / 2 + 20);
|
||||||
g.setFont('6x8', 1.6);
|
g.setFont('6x8', 1.6);
|
||||||
g.drawString(' BPM', g.getWidth() / 2 + 42, g.getHeight() / 2 + 20);
|
g.drawString(' BPM', g.getWidth() / 2 + 42, g.getHeight() / 2 + 20);
|
||||||
|
@ -83,6 +75,8 @@ function drawScreen(message) {
|
||||||
if (currentHeartRate !== null && currentHeartRate > 0) {
|
if (currentHeartRate !== null && currentHeartRate > 0) {
|
||||||
g.setFont('6x8', 4);
|
g.setFont('6x8', 4);
|
||||||
g.drawString(currentHeartRate.toString(), g.getWidth() / 2, g.getHeight() / 2 + 10);
|
g.drawString(currentHeartRate.toString(), g.getWidth() / 2, g.getHeight() / 2 + 10);
|
||||||
|
g.setFont('6x8', 1.6);
|
||||||
|
g.drawString(' BPM', g.getWidth() / 2 + 42, g.getHeight() / 2 + 12);
|
||||||
} else {
|
} else {
|
||||||
g.setFont('6x8', 2);
|
g.setFont('6x8', 2);
|
||||||
g.drawString('No data', g.getWidth() / 2, g.getHeight() / 2 + 10);
|
g.drawString('No data', g.getWidth() / 2, g.getHeight() / 2 + 10);
|
||||||
|
@ -96,14 +90,78 @@ function drawScreen(message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveDataToCSV() {
|
function saveDataToCSV() {
|
||||||
let csvContent = "Timestamp,Heart Rate\n";
|
let date = new Date();
|
||||||
|
let dateStr = require("locale").date(date);
|
||||||
|
let timeStr = require("locale").time(date, 1);
|
||||||
|
let seconds = date.getSeconds();
|
||||||
|
let timestamp = `${dateStr} ${timeStr}:${seconds}`;
|
||||||
|
|
||||||
|
// Check if 10 seconds have passed since the last heart rate log
|
||||||
|
if (date.getTime() - lastHeartRateLogTimestamp >= 10 * 1000) {
|
||||||
|
logData.push({ timestamp: timestamp, heartRate: currentHeartRate });
|
||||||
|
lastHeartRateLogTimestamp = date.getTime(); // Update the last heart rate log timestamp
|
||||||
|
|
||||||
|
// Log data to CSV
|
||||||
|
let csvContent = "Timestamp,Heart Rate,HRV (ms)\n";
|
||||||
logData.forEach(entry => {
|
logData.forEach(entry => {
|
||||||
csvContent += `${entry.timestamp},${entry.heartRate}\n`;
|
if (entry.heartRate > 0) {
|
||||||
|
let hrv = hrvValues[entry.timestamp] || ""; // Get HRV value for the timestamp
|
||||||
|
csvContent += `${entry.timestamp},${entry.heartRate},${hrv}\n`;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
require("Storage").write("heart_rate_data.csv", csvContent);
|
require("Storage").write("heart_rate_data.csv", csvContent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setWatch(function() {
|
function handleHeartRate(hrm) {
|
||||||
|
if (isMeasuring) {
|
||||||
|
currentHeartRate = hrm.bpm;
|
||||||
|
drawScreen();
|
||||||
|
|
||||||
|
// Log data to CSV
|
||||||
|
saveDataToCSV();
|
||||||
|
|
||||||
|
// Estimate RR intervals
|
||||||
|
let rrIntervals = estimateRRIntervals(bpmValues);
|
||||||
|
|
||||||
|
// Calculate HRV
|
||||||
|
calculateHRV(rrIntervals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function estimateRRIntervals(rawData) {
|
||||||
|
let rrIntervals = [];
|
||||||
|
for (let i = 1; i < rawData.length; i++) {
|
||||||
|
let rrInterval = rawData[i] - rawData[i - 1];
|
||||||
|
rrIntervals.push(rrInterval);
|
||||||
|
}
|
||||||
|
return rrIntervals;
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateHRV(rawData) {
|
||||||
|
// Calculate HRV with SDNN method for each slot in hrvSlots
|
||||||
|
let sdnn = calcSDNN(rawData);
|
||||||
|
hrvValues[Date.now()] = sdnn; // Store HRV value with current timestamp
|
||||||
|
|
||||||
|
// Log HRV data if 5 minutes have elapsed
|
||||||
|
if (Date.now() - lastHeartRateLogTimestamp >= 5 * 60 * 1000) {
|
||||||
|
console.log("Recalculating HRV...");
|
||||||
|
saveDataToCSV(); // Save both heart rate and HRV data to the CSV file
|
||||||
|
lastHeartRateLogTimestamp = Date.now(); // Update the timestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcSDNN(rrIntervals) {
|
||||||
|
let sumOfDifferencesSquared = 0;
|
||||||
|
let meanRRInterval = rrIntervals.reduce((acc, val) => acc + val, 0) / rrIntervals.length;
|
||||||
|
rrIntervals.forEach(rr => {
|
||||||
|
sumOfDifferencesSquared += Math.pow(rr - meanRRInterval, 2);
|
||||||
|
});
|
||||||
|
let meanOfDifferencesSquared = sumOfDifferencesSquared / (rrIntervals.length - 1);
|
||||||
|
return Math.sqrt(meanOfDifferencesSquared);
|
||||||
|
}
|
||||||
|
|
||||||
|
setWatch(function () {
|
||||||
if (!isMeasuring) {
|
if (!isMeasuring) {
|
||||||
startMeasure();
|
startMeasure();
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue