mirror of https://github.com/espruino/BangleApps
commit
50a149d580
14
apps.json
14
apps.json
|
@ -1108,6 +1108,20 @@
|
|||
{"name":"openstmap.app.js","url":"app.js"},
|
||||
{"name":"openstmap.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
},
|
||||
{ "id": "activepedom",
|
||||
"name": "Active Pedometer",
|
||||
"shortName":"Active Pedometer",
|
||||
"icon": "app.png",
|
||||
"version":"0.01",
|
||||
"description": "Pedometer that filters out arm movement and displays a step goal progress.",
|
||||
"tags": "outdoors,widget",
|
||||
"type":"widget",
|
||||
"storage": [
|
||||
{"name":"activepedom.wid.js","url":"widget.js"},
|
||||
{"name":"activepedom.settings.js","url":"settings.js"},
|
||||
{"name":"activepedom.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
},
|
||||
{ "id": "tabata",
|
||||
"name": "Tabata",
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 370 B |
Binary file not shown.
After Width: | Height: | Size: 374 B |
Binary file not shown.
After Width: | Height: | Size: 338 B |
|
@ -0,0 +1 @@
|
|||
0.01: New Widget!
|
|
@ -0,0 +1,38 @@
|
|||
# Improved pedometer
|
||||
Pedometer that filters out arm movement and displays a step goal progress.
|
||||
|
||||
I changed the step counting algorithm completely.
|
||||
Now every step is counted when in status 'active', if the time difference between two steps is not too short or too long.
|
||||
To get in 'active' mode, you have to reach the step threshold before the active timer runs out.
|
||||
When you reach the step threshold, the steps needed to reach the threshold are counted as well.
|
||||
|
||||
## Screenshots
|
||||
* 600 steps
|
||||

|
||||
|
||||
* 1600 steps
|
||||

|
||||
|
||||
* 10600 steps
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
* Two line display
|
||||
* Large number for good readability
|
||||
* Small number with the exact steps counted
|
||||
* Large number is displayed in green when status is 'active'
|
||||
* Progress bar for step goal
|
||||
* Counts steps only if they are reached in a certain time
|
||||
* Filters out steps where time between two steps is too long or too short
|
||||
* Step detection sensitivity from firmware can be configured
|
||||
* Steps are saved to a file and read-in at start (to not lose step progress)
|
||||
* Settings can be changed in Settings - App/widget settings - Active Pedometer
|
||||
|
||||
## Development version
|
||||
|
||||
* https://github.com/Purple-Tentacle/BangleAppsDev/tree/master/apps/pedometer
|
||||
|
||||
## Requests
|
||||
|
||||
If you have any feature requests, please post in this forum thread: http://forum.espruino.com/conversations/345754/
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwIGDvAEDgP+ApMD/4FVEZY1FABcP8AFDn/wAod/AocB//4AoUHAokPAokf5/8AocfAoc+j5HDvgFEvEf7+AAoP4AoJCC+E/54qCsE/wYkDn+AAos8AohZDj/AAohrEp4FEs5xEuJfDgF5Aon4GgYFBGgZOBnyJD+EeYgfgj4FEh6VD4AFDh+AAIJMCBoIFFLQQtBgYFCHIIFDjA3BC4I="))
|
Binary file not shown.
After Width: | Height: | Size: 836 B |
|
@ -0,0 +1,81 @@
|
|||
// This file should contain exactly one function, which shows the app's settings
|
||||
/**
|
||||
* @param {function} back Use back() to return to settings menu
|
||||
*/
|
||||
(function(back) {
|
||||
const SETTINGS_FILE = 'activepedom.settings.json';
|
||||
|
||||
// initialize with default settings...
|
||||
let s = {
|
||||
'cMaxTime' : 1100,
|
||||
'cMinTime' : 240,
|
||||
'stepThreshold' : 30,
|
||||
'intervalResetActive' : 30000,
|
||||
'stepSensitivity' : 80,
|
||||
'stepGoal' : 10000,
|
||||
};
|
||||
// ...and overwrite them with any saved values
|
||||
// This way saved values are preserved if a new version adds more settings
|
||||
const storage = require('Storage');
|
||||
const saved = storage.readJSON(SETTINGS_FILE, 1) || {};
|
||||
for (const key in saved) {
|
||||
s[key] = saved[key];
|
||||
}
|
||||
|
||||
// creates a function to safe a specific setting, e.g. save('color')(1)
|
||||
function save(key) {
|
||||
return function (value) {
|
||||
s[key] = value;
|
||||
storage.write(SETTINGS_FILE, s);
|
||||
WIDGETS["activepedom"].draw();
|
||||
};
|
||||
}
|
||||
|
||||
const menu = {
|
||||
'': { 'title': 'Active Pedometer' },
|
||||
'< Back': back,
|
||||
'Max time (ms)': {
|
||||
value: s.cMaxTime,
|
||||
min: 0,
|
||||
max: 10000,
|
||||
step: 100,
|
||||
onchange: save('cMaxTime'),
|
||||
},
|
||||
'Min time (ms)': {
|
||||
value: s.cMinTime,
|
||||
min: 0,
|
||||
max: 500,
|
||||
step: 10,
|
||||
onchange: save('cMinTime'),
|
||||
},
|
||||
'Step threshold': {
|
||||
value: s.stepThreshold,
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 1,
|
||||
onchange: save('stepThreshold'),
|
||||
},
|
||||
'Act.Res. (ms)': {
|
||||
value: s.intervalResetActive,
|
||||
min: 100,
|
||||
max: 100000,
|
||||
step: 1000,
|
||||
onchange: save('intervalResetActive'),
|
||||
},
|
||||
'Step sens.': {
|
||||
value: s.stepSensitivity,
|
||||
min: 0,
|
||||
max: 1000,
|
||||
step: 10,
|
||||
onchange: save('stepSensitivity'),
|
||||
},
|
||||
'Step goal': {
|
||||
value: s.stepGoal,
|
||||
min: 1000,
|
||||
max: 100000,
|
||||
step: 1000,
|
||||
onchange: save('stepGoal'),
|
||||
},
|
||||
};
|
||||
E.showMenu(menu);
|
||||
});
|
|
@ -0,0 +1,180 @@
|
|||
(() => {
|
||||
var stepTimeDiff = 9999; //Time difference between two steps
|
||||
var startTimeStep = new Date(); //set start time
|
||||
var stopTimeStep = 0; //Time after one step
|
||||
var timerResetActive = 0; //timer to reset active
|
||||
var steps = 0; //steps taken
|
||||
var stepsCounted = 0; //active steps counted
|
||||
var active = 0; //x steps in y seconds achieved
|
||||
var stepGoalPercent = 0; //percentage of step goal
|
||||
var stepGoalBarLength = 0; //length og progress bar
|
||||
var lastUpdate = new Date();
|
||||
var width = 45;
|
||||
|
||||
var stepsTooShort = 0;
|
||||
var stepsTooLong = 0;
|
||||
var stepsOutsideTime = 0;
|
||||
|
||||
//define default settings
|
||||
const DEFAULTS = {
|
||||
'cMaxTime' : 1100,
|
||||
'cMinTime' : 240,
|
||||
'stepThreshold' : 30,
|
||||
'intervalResetActive' : 30000,
|
||||
'stepSensitivity' : 80,
|
||||
'stepGoal' : 10000,
|
||||
};
|
||||
const SETTINGS_FILE = 'activepedom.settings.json';
|
||||
const PEDOMFILE = "activepedom.steps.json";
|
||||
|
||||
let settings;
|
||||
//load settings
|
||||
function loadSettings() {
|
||||
settings = require('Storage').readJSON(SETTINGS_FILE, 1) || {};
|
||||
}
|
||||
//return setting
|
||||
function setting(key) {
|
||||
if (!settings) { loadSettings(); }
|
||||
return (key in settings) ? settings[key] : DEFAULTS[key];
|
||||
}
|
||||
|
||||
function setStepSensitivity(s) {
|
||||
function sqr(x) { return x*x; }
|
||||
var X=sqr(8192-s);
|
||||
var Y=sqr(8192+s);
|
||||
Bangle.setOptions({stepCounterThresholdLow:X,stepCounterThresholdHigh:Y});
|
||||
}
|
||||
|
||||
//format number to make them shorter
|
||||
function kFormatter(num) {
|
||||
if (num <= 999) return num; //smaller 1.000, return 600 as 600
|
||||
if (num >= 1000 && num < 10000) { //between 1.000 and 10.000
|
||||
num = Math.floor(num/100)*100;
|
||||
return (num / 1000).toFixed(1).replace(/\.0$/, '') + 'k'; //return 1600 as 1.6k
|
||||
}
|
||||
if (num >= 10000) { //greater 10.000
|
||||
num = Math.floor(num/1000)*1000;
|
||||
return (num / 1000).toFixed(1).replace(/\.0$/, '') + 'k'; //return 10.600 as 10k
|
||||
}
|
||||
}
|
||||
|
||||
//Set Active to 0
|
||||
function resetActive() {
|
||||
active = 0;
|
||||
steps = 0;
|
||||
if (Bangle.isLCDOn()) WIDGETS["activepedom"].draw();
|
||||
}
|
||||
|
||||
function calcSteps() {
|
||||
stopTimeStep = new Date(); //stop time after each step
|
||||
stepTimeDiff = stopTimeStep - startTimeStep; //time between steps in milliseconds
|
||||
startTimeStep = new Date(); //start time again
|
||||
|
||||
//Remove step if time between first and second step is too long
|
||||
if (stepTimeDiff >= setting('cMaxTime')) { //milliseconds
|
||||
stepsTooLong++; //count steps which are note counted, because time too long
|
||||
steps--;
|
||||
}
|
||||
|
||||
//Remove step if time between first and second step is too short
|
||||
if (stepTimeDiff <= setting('cMinTime')) { //milliseconds
|
||||
stepsTooShort++; //count steps which are note counted, because time too short
|
||||
steps--;
|
||||
}
|
||||
|
||||
if (steps >= setting('stepThreshold')) {
|
||||
if (active == 0) {
|
||||
stepsCounted = stepsCounted + (setting('stepThreshold') -1) ; //count steps needed to reach active status, last step is counted anyway, so treshold -1
|
||||
stepsOutsideTime = stepsOutsideTime - 10; //substract steps needed to reac active status
|
||||
}
|
||||
active = 1;
|
||||
clearInterval(timerResetActive); //stop timer which resets active
|
||||
timerResetActive = setInterval(resetActive, setting('intervalResetActive')); //reset active after timer runs out
|
||||
steps = 0;
|
||||
}
|
||||
|
||||
if (active == 1) {
|
||||
stepsCounted++; //count steps
|
||||
}
|
||||
else {
|
||||
stepsOutsideTime++;
|
||||
}
|
||||
}
|
||||
|
||||
function draw() {
|
||||
var height = 23; //width is deined globally
|
||||
var stepsDisplayLarge = kFormatter(stepsCounted);
|
||||
|
||||
//Check if same day
|
||||
let date = new Date();
|
||||
if (lastUpdate.getDate() == date.getDate()){ //if same day
|
||||
}
|
||||
else {
|
||||
stepsCounted = 1; //set stepcount to 1
|
||||
}
|
||||
lastUpdate = date;
|
||||
|
||||
g.reset();
|
||||
g.clearRect(this.x, this.y, this.x+width, this.y+height);
|
||||
|
||||
//draw numbers
|
||||
if (active == 1) g.setColor(0x07E0); //green
|
||||
else g.setColor(0xFFFF); //white
|
||||
g.setFont("6x8", 2);
|
||||
g.drawString(stepsDisplayLarge,this.x+1,this.y); //first line, big number
|
||||
g.setFont("6x8", 1);
|
||||
g.setColor(0xFFFF); //white
|
||||
g.drawString(stepsCounted,this.x+1,this.y+14); //second line, small number
|
||||
|
||||
//draw step goal bar
|
||||
stepGoalPercent = (stepsCounted / setting('stepGoal')) * 100;
|
||||
stepGoalBarLength = width / 100 * stepGoalPercent;
|
||||
if (stepGoalBarLength > width) stepGoalBarLength = width; //do not draw across width of widget
|
||||
g.setColor(0x7BEF); //grey
|
||||
g.fillRect(this.x, this.y+height, this.x+width, this.y+height); // draw background bar
|
||||
g.setColor(0xFFFF); //white
|
||||
g.fillRect(this.x, this.y+height, this.x+1, this.y+height-1); //draw start of bar
|
||||
g.fillRect(this.x+width, this.y+height, this.x+width-1, this.y+height-1); //draw end of bar
|
||||
g.fillRect(this.x, this.y+height, this.x+stepGoalBarLength, this.y+height); // draw progress bar
|
||||
}
|
||||
|
||||
//This event is called just before the device shuts down for commands such as reset(), load(), save(), E.reboot() or Bangle.off()
|
||||
E.on('kill', () => {
|
||||
let d = { //define array to write to file
|
||||
lastUpdate : lastUpdate.toISOString(),
|
||||
stepsToday : stepsCounted,
|
||||
stepsTooShort : stepsTooShort,
|
||||
stepsTooLong : stepsTooLong,
|
||||
stepsOutsideTime : stepsOutsideTime
|
||||
};
|
||||
require("Storage").write(PEDOMFILE,d); //write array to file
|
||||
});
|
||||
|
||||
//When Step is registered by firmware
|
||||
Bangle.on('step', (up) => {
|
||||
steps++; //increase step count
|
||||
calcSteps();
|
||||
if (Bangle.isLCDOn()) WIDGETS["activepedom"].draw();
|
||||
});
|
||||
|
||||
// redraw when the LCD turns on
|
||||
Bangle.on('lcdPower', function(on) {
|
||||
if (on) WIDGETS["activepedom"].draw();
|
||||
});
|
||||
|
||||
//Read data from file and set variables
|
||||
let pedomData = require("Storage").readJSON(PEDOMFILE,1);
|
||||
if (pedomData) {
|
||||
if (pedomData.lastUpdate) lastUpdate = new Date(pedomData.lastUpdate);
|
||||
stepsCounted = pedomData.stepsToday|0;
|
||||
stepsTooShort = pedomData.stepsTooShort;
|
||||
stepsTooLong = pedomData.stepsTooLong;
|
||||
stepsOutsideTime = pedomData.stepsOutsideTime;
|
||||
}
|
||||
|
||||
setStepSensitivity(setting('stepSensitivity')); //set step sensitivity (80 is standard, 400 is muss less sensitive)
|
||||
|
||||
//Add widget
|
||||
WIDGETS["activepedom"]={area:"tl",width:width,draw:draw};
|
||||
|
||||
})();
|
Loading…
Reference in New Issue