Add settings for buzz; more timeouts to better detect activities; reduce memory usage

master
Marco Heiming 2022-01-11 16:04:54 +01:00
parent 83aa32ee84
commit a3ada12a92
3 changed files with 92 additions and 34 deletions

View File

@ -5518,7 +5518,11 @@
"readme": "README.md", "readme": "README.md",
"storage": [ "storage": [
{"name":"banglexercise.app.js","url":"app.js"}, {"name":"banglexercise.app.js","url":"app.js"},
{"name":"banglexercise.img","url":"app-icon.js","evaluate":true} {"name":"banglexercise.img","url":"app-icon.js","evaluate":true},
{"name":"banglexercise.settings.js","url":"settings.js"}
],
"data": [
{"name":"banglexercise.json"}
] ]
} }
] ]

View File

@ -9,10 +9,11 @@ let historyAvgZ = [];
let historySlopeY = []; let historySlopeY = [];
let historySlopeZ = []; let historySlopeZ = [];
let lastZeroPassType; let lastZeroPassCameFromPositive;
let lastZeroPassTime = 0; let lastZeroPassTime = 0;
let lastExerciseCmpltTime = 0; let lastExerciseCompletionTime = 0;
let lastExerciseHalfCompletionTime = 0;
let exerciseType = { let exerciseType = {
"id": "", "id": "",
@ -22,19 +23,23 @@ let exerciseType = {
// add new exercises here: // add new exercises here:
const exerciseTypes = [{ const exerciseTypes = [{
"id": "pushup", "id": "pushup",
"name": "Push ups", "name": "push ups",
"useYaxe": true, "useYaxe": true,
"useZaxe": false, "useZaxe": false,
"thresholdY": 2500, "thresholdY": 2500,
"thresholdTime": 1400 // mininmal time between two push ups "thresholdMinTime": 1400, // mininmal time between two push ups in ms
"thresholdMaxTime": 5000, // maximal time between two push ups in ms
"thresholdMinDurationTime": 700, // mininmal duration of half a push ups in ms
}, },
{ {
"id": "curl", "id": "curl",
"name": "Curls", "name": "curls",
"useYaxe": true, "useYaxe": true,
"useZaxe": false, "useZaxe": false,
"thresholdY": 2500, "thresholdY": 2500,
"thresholdTime": 1000 // mininmal time between two curls "thresholdMinTime": 1000, // mininmal time between two curls in ms
"thresholdMaxTime": 5000, // maximal time between two curls in ms
"thresholdMinDurationTime": 500, // mininmal duration of half a push ups in ms
} }
]; ];
let exerciseCounter = 0; let exerciseCounter = 0;
@ -47,6 +52,10 @@ const avgSize = 6;
let hrtValue; let hrtValue;
let settings = storage.readJSON("banglexercise.json", 1) || {
'buzz': true
};
function showMainMenu() { function showMainMenu() {
let menu; let menu;
menu = { menu = {
@ -64,7 +73,7 @@ function showMainMenu() {
}); });
if (exerciseCounter > 0) { if (exerciseCounter > 0) {
menu["----"] = { menu["--------"] = {
value: "" value: ""
}; };
menu["Last:"] = { menu["Last:"] = {
@ -91,6 +100,8 @@ function accelHandler(accel) {
if (historyY.length > avgSize / 2) { if (historyY.length > avgSize / 2) {
const avgY = E.sum(historyY) / historyY.length; const avgY = E.sum(historyY) / historyY.length;
historyAvgY.push([t, avgY]); historyAvgY.push([t, avgY]);
while (historyAvgY.length > avgSize)
historyAvgY.shift();
} }
} }
@ -103,6 +114,8 @@ function accelHandler(accel) {
if (historyZ.length > avgSize / 2) { if (historyZ.length > avgSize / 2) {
const avgZ = E.sum(historyZ) / historyZ.length; const avgZ = E.sum(historyZ) / historyZ.length;
historyAvgZ.push([t, avgZ]); historyAvgZ.push([t, avgZ]);
while (historyAvgZ.length > avgSize)
historyAvgZ.shift();
} }
} }
@ -113,7 +126,6 @@ function accelHandler(accel) {
const p1 = historyAvgY[l - 2]; const p1 = historyAvgY[l - 2];
const p2 = historyAvgY[l - 1]; const p2 = historyAvgY[l - 1];
const slopeY = (p2[1] - p1[1]) / (p2[0] / 1000 - p1[0] / 1000); const slopeY = (p2[1] - p1[1]) / (p2[0] / 1000 - p1[0] / 1000);
// we use this data for exercises which can be detected by using Y axis data // we use this data for exercises which can be detected by using Y axis data
switch (exerciseType.id) { switch (exerciseType.id) {
case "pushup": case "pushup":
@ -154,7 +166,9 @@ function isValidYAxisExercise(slopeY, t) {
if (!exerciseType) return; if (!exerciseType) return;
const thresholdY = exerciseType.thresholdY; const thresholdY = exerciseType.thresholdY;
const thresholdTime = exerciseType.thresholdTime; const thresholdMinTime = exerciseType.thresholdMinTime;
const thresholdMaxTime = exerciseType.thresholdMaxTime;
const thresholdMinDurationTime = exerciseType.thresholdMinDurationTime;
const exerciseName = exerciseType.name; const exerciseName = exerciseType.name;
if (Math.abs(slopeY) >= thresholdY) { if (Math.abs(slopeY) >= thresholdY) {
@ -164,43 +178,61 @@ function isValidYAxisExercise(slopeY, t) {
const lSlopeY = historySlopeY.length; const lSlopeY = historySlopeY.length;
if (lSlopeY > 1) { if (lSlopeY > 1) {
const p1 = historySlopeY[lSlopeY - 2][1]; const p1 = historySlopeY[lSlopeY - 1][1];
const p2 = historySlopeY[lSlopeY - 1][1]; const p2 = historySlopeY[lSlopeY - 2][1];
if (p1 > 0 && p2 < 0) { if (p1 > 0 && p2 < 0) {
if (lastZeroPassType == "-+") { if (lastZeroPassCameFromPositive == false) {
lastExerciseHalfCompletionTime = t;
console.log(t, exerciseName + " half complete..."); console.log(t, exerciseName + " half complete...");
layout.progress.label = "*"; layout.progress.label = "½";
layout.render(); layout.render();
} }
lastZeroPassType = "+-"; lastZeroPassCameFromPositive = true;
lastZeroPassTime = t; lastZeroPassTime = t;
} }
if (p2 > 0 && p1 < 0) { if (p2 > 0 && p1 < 0) {
if (lastZeroPassType == "+-") { if (lastZeroPassCameFromPositive == true) {
// potential complete exercise. Let's check the time difference... const tDiffLastExercise = t - lastExerciseCompletionTime;
const tDiffLastPushUp = t - lastExerciseCmpltTime;
const tDiffStart = t - tStart; const tDiffStart = t - tStart;
console.log(t, exerciseName + " maybe complete?", Math.round(tDiffLastPushUp), Math.round(tDiffStart)); console.log(t, exerciseName + " maybe complete?", Math.round(tDiffLastExercise), Math.round(tDiffStart));
if ((lastExerciseCmpltTime <= 0 && tDiffStart >= thresholdTime) || tDiffLastPushUp >= thresholdTime) { // check minimal time between exercises:
console.log(t, exerciseName + " complete!!!"); if ((lastExerciseCompletionTime <= 0 && tDiffStart >= thresholdMinTime) || tDiffLastExercise >= thresholdMinTime) {
lastExerciseCmpltTime = t; // check maximal time between exercises:
exerciseCounter++; if (lastExerciseCompletionTime <= 0 || tDiffLastExercise <= thresholdMaxTime) {
layout.count.label = exerciseCounter; // check minimal duration of exercise:
layout.progress.label = ""; const tDiffExerciseHalfCompletion = t - lastExerciseHalfCompletionTime;
layout.render(); if (tDiffExerciseHalfCompletion > thresholdMinDurationTime) {
console.log(t, exerciseName + " complete!!!");
Bangle.buzz(100, 0.4); // TODO make configurable lastExerciseCompletionTime = t;
exerciseCounter++;
layout.count.label = exerciseCounter;
layout.progress.label = "";
layout.render();
if (settings.buzz)
Bangle.buzz(100, 0.4);
} else {
console.log(t, exerciseName + " to quick for duration time threshold!");
lastExerciseCompletionTime = t;
}
} else {
console.log(t, exerciseName + " to slow for time threshold!");
lastExerciseCompletionTime = t;
}
} else { } else {
console.log(t, exerciseName + " to quick for time threshold!"); console.log(t, exerciseName + " to quick for time threshold!");
lastExerciseCompletionTime = t;
} }
} }
lastZeroPassType = "-+"; lastZeroPassCameFromPositive = false;
lastZeroPassTime = t; lastZeroPassTime = t;
} }
} }
@ -216,9 +248,10 @@ function reset() {
historySlopeY = []; historySlopeY = [];
historySlopeZ = []; historySlopeZ = [];
lastZeroPassType = ""; lastZeroPassCameFromPositive = undefined;
lastZeroPassTime = 0; lastZeroPassTime = 0;
lastExerciseCmpltTime = 0; lastExerciseHalfCompletionTime = 0;
lastExerciseCompletionTime = 0;
exerciseCounter = 0; exerciseCounter = 0;
tStart = 0; tStart = 0;
} }
@ -300,18 +333,18 @@ function startRecording() {
Bangle.setPollInterval(80); // 12.5 Hz Bangle.setPollInterval(80); // 12.5 Hz
Bangle.on('accel', accelHandler); Bangle.on('accel', accelHandler);
Bangle.buzz(200, 1);
tStart = new Date().getTime(); tStart = new Date().getTime();
recordActive = true; recordActive = true;
if (settings.buzz)
Bangle.buzz(200, 1);
} }
function stopRecording() { function stopRecording() {
if (!recordActive) return; if (!recordActive) return;
g.clear(1); g.clear(1);
Bangle.setHRMPower(0, "banglexercise");
Bangle.removeListener('accel', accelHandler); Bangle.removeListener('accel', accelHandler);
Bangle.setHRMPower(0, "banglexercise");
showMainMenu(); showMainMenu();
recordActive = false; recordActive = false;
} }

View File

@ -0,0 +1,21 @@
(function(back) {
const SETTINGS_FILE = "banglexercise.json";
const storage = require('Storage');
let settings = storage.readJSON(SETTINGS_FILE, 1) || {};
function save(key, value) {
settings[key] = value;
storage.write(SETTINGS_FILE, settings);
}
E.showMenu({
'': { 'title': 'BanglExercise' },
'< Back': back,
'Buzz': {
value: "buzz" in settings ? settings.buzz : false,
format: () => (settings.buzz ? 'Yes' : 'No'),
onchange: () => {
settings.buzz = !settings.buzz;
save('buzz', settings.buzz);
}
}
});
});