Add settings for buzz; more timeouts to better detect activities; reduce memory usage
parent
83aa32ee84
commit
a3ada12a92
|
|
@ -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"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue