activepedom 0.03
parent
af0ac4041c
commit
4b512af0e2
|
|
@ -1,2 +1,3 @@
|
||||||
0.01: New Widget!
|
0.01: New Widget!
|
||||||
0.02: Distance calculation and display
|
0.02: Distance calculation and display
|
||||||
|
0.03: Data logging and display
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Active Pedometer
|
# Active Pedometer
|
||||||
Pedometer that filters out arm movement and displays a step goal progress.
|
Pedometer that filters out arm movement and displays a step goal progress.
|
||||||
|
|
||||||
I changed the step counting algorithm completely.
|
I changed the step counting algorithm completely.
|
||||||
|
|
@ -6,6 +6,8 @@ Now every step is counted when in status 'active', if the time difference betwee
|
||||||
To get in 'active' mode, you have to reach the step threshold before the active timer runs out.
|
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.
|
When you reach the step threshold, the steps needed to reach the threshold are counted as well.
|
||||||
|
|
||||||
|
Steps are saved to a datafile every 5 minutes. You can watch a graph using the app.
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
* 600 steps
|
* 600 steps
|
||||||

|

|
||||||
|
|
@ -30,6 +32,22 @@ When you reach the step threshold, the steps needed to reach the threshold are c
|
||||||
* Steps are saved to a file and read-in at start (to not lose step progress)
|
* 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
|
* Settings can be changed in Settings - App/widget settings - Active Pedometer
|
||||||
|
|
||||||
|
## Data storage
|
||||||
|
|
||||||
|
* Data is stored to a file
|
||||||
|
* Format: now,stepsCounted,active,stepsTooShort,stepsTooLong,stepsOutsideTime
|
||||||
|
* now is UNIX timestamp in ms
|
||||||
|
* You can chose the app to watch a steps graph
|
||||||
|
* You can import the file into Excel
|
||||||
|
* The file does not include a header
|
||||||
|
* You can convert UNIX timestamp to a date in Excel using this formula: =DATUM(1970;1;1)+(LINKS(A2;10)/86400)
|
||||||
|
* You have to format the cell with the formula to a date cell. Example: JJJJ-MM-TT-hh-mm-ss
|
||||||
|
|
||||||
|
## App
|
||||||
|
|
||||||
|
* The app accesses the data stored for the current day
|
||||||
|
* Timespan is choseable (1h, 4h, 8h, 12h, 16h, 20, 24h), standard is 24h, the whole current day
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
|
|
||||||
* Max time (ms): Maximum time between two steps in milliseconds, steps will not be counted if exceeded. Standard: 1100
|
* Max time (ms): Maximum time between two steps in milliseconds, steps will not be counted if exceeded. Standard: 1100
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,133 @@
|
||||||
|
(() => {
|
||||||
|
|
||||||
|
const storage = require("Storage");
|
||||||
|
var history = 86400000; // 28800000=8h 43200000=12h //86400000=24h
|
||||||
|
|
||||||
|
//Convert ms to time
|
||||||
|
function getTime(t) {
|
||||||
|
date = new Date(t);
|
||||||
|
offset = date.getTimezoneOffset() / 60;
|
||||||
|
//var milliseconds = parseInt((t % 1000) / 100),
|
||||||
|
seconds = Math.floor((t / 1000) % 60);
|
||||||
|
minutes = Math.floor((t / (1000 * 60)) % 60);
|
||||||
|
hours = Math.floor((t / (1000 * 60 * 60)) % 24);
|
||||||
|
hours = hours - offset;
|
||||||
|
hours = (hours < 10) ? "0" + hours : hours;
|
||||||
|
minutes = (minutes < 10) ? "0" + minutes : minutes;
|
||||||
|
seconds = (seconds < 10) ? "0" + seconds : seconds;
|
||||||
|
return hours + ":" + minutes + ":" + seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDate(t) {
|
||||||
|
date = new Date(t*1);
|
||||||
|
year = date.getFullYear();
|
||||||
|
month = date.getMonth()+1; //month is zero-based
|
||||||
|
day = date.getDate();
|
||||||
|
month = (month < 10) ? "0" + month : month;
|
||||||
|
day = (day < 10) ? "0" + day : day;
|
||||||
|
return year + "-" + month + "-" + day;
|
||||||
|
}
|
||||||
|
|
||||||
|
//columns: 0=time, 1=stepsCounted, 2=active, 3=stepsTooShort, 4=stepsTooLong, 5=stepsOutsideTime
|
||||||
|
function getArrayFromCSV(file, column) {
|
||||||
|
i = 0;
|
||||||
|
array = [];
|
||||||
|
now = new Date();
|
||||||
|
while ((nextLine = file.readLine())) { //as long as there is a next line
|
||||||
|
if(nextLine) {
|
||||||
|
dataSplitted = nextLine.split(','); //split line,
|
||||||
|
diff = now - dataSplitted[0]; //calculate difference between now and stored time
|
||||||
|
if (diff <= history) { //only entries from the last x ms
|
||||||
|
array.push(dataSplitted[column]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawGraph() {
|
||||||
|
//times
|
||||||
|
// actives = getArrayFromCSV(csvFile, 2);
|
||||||
|
// shorts = getArrayFromCSV(csvFile, 3);
|
||||||
|
// longs = getArrayFromCSV(csvFile, 4);
|
||||||
|
// outsides = getArrayFromCSV(csvFile, 5); //array.push(dataSplitted[5].slice(0,-1));
|
||||||
|
now = new Date();
|
||||||
|
month = now.getMonth() + 1;
|
||||||
|
if (month < 10) month = "0" + month;
|
||||||
|
filename = filename = "activepedom-" + now.getFullYear() + month + now.getDate() + ".data";
|
||||||
|
var csvFile = storage.open(filename, "r");
|
||||||
|
times = getArrayFromCSV(csvFile, 0);
|
||||||
|
first = getDate(times[0]) + " " + getTime(times[0]);
|
||||||
|
last = getDate (times[times.length-1]) + " " + getTime(times[times.length-1]);
|
||||||
|
//free memory
|
||||||
|
csvFile = undefined;
|
||||||
|
times = undefined;
|
||||||
|
|
||||||
|
//steps
|
||||||
|
var csvFile = storage.open(filename, "r");
|
||||||
|
steps = getArrayFromCSV(csvFile, 1);
|
||||||
|
//define y-axis grid labels
|
||||||
|
stepsLastEntry = steps[steps.length-1];
|
||||||
|
if (stepsLastEntry < 1000) gridyValue = 100;
|
||||||
|
if (stepsLastEntry >= 1000 && stepsLastEntry < 10000) gridyValue = 500;
|
||||||
|
if (stepsLastEntry > 10000) gridyValue = 5000;
|
||||||
|
|
||||||
|
//draw
|
||||||
|
drawMenu();
|
||||||
|
g.drawString("First: " + first, 40, 30);
|
||||||
|
g.drawString(" Last: " + last, 40, 40);
|
||||||
|
require("graph").drawLine(g, steps, {
|
||||||
|
//title: "Steps Counted",
|
||||||
|
axes : true,
|
||||||
|
gridy : gridyValue,
|
||||||
|
y : 50, //offset on screen
|
||||||
|
x : 5, //offset on screen
|
||||||
|
});
|
||||||
|
//free memory from big variables
|
||||||
|
allData = undefined;
|
||||||
|
allDataFile = undefined;
|
||||||
|
csvFile = undefined;
|
||||||
|
times = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawMenu () {
|
||||||
|
g.clear();
|
||||||
|
g.setFont("6x8", 1);
|
||||||
|
g.drawString("BTN1:Timespan | BTN2:Draw", 20, 10);
|
||||||
|
g.drawString("Timespan: " + history/1000/60/60 + " hours", 20, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
setWatch(function() { //BTN1
|
||||||
|
switch(history) {
|
||||||
|
case 3600000 : //1h
|
||||||
|
history = 14400000; //4h
|
||||||
|
break;
|
||||||
|
case 86400000 : //24
|
||||||
|
history = 3600000; //1h
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
history = history + 14400000; //4h
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
drawMenu();
|
||||||
|
}, BTN1, {edge:"rising", debounce:50, repeat:true});
|
||||||
|
|
||||||
|
setWatch(function() { //BTN2
|
||||||
|
g.setFont("6x8", 2);
|
||||||
|
g.drawString ("Drawing...",30,60);
|
||||||
|
drawGraph();
|
||||||
|
}, BTN2, {edge:"rising", debounce:50, repeat:true});
|
||||||
|
|
||||||
|
setWatch(function() { //BTN3
|
||||||
|
}, BTN3, {edge:"rising", debounce:50, repeat:true});
|
||||||
|
|
||||||
|
setWatch(function() { //BTN4
|
||||||
|
}, BTN4, {edge:"rising", debounce:50, repeat:true});
|
||||||
|
|
||||||
|
setWatch(function() { //BTN5
|
||||||
|
}, BTN5, {edge:"rising", debounce:50, repeat:true});
|
||||||
|
|
||||||
|
drawMenu();
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
@ -3,13 +3,14 @@
|
||||||
var startTimeStep = new Date(); //set start time
|
var startTimeStep = new Date(); //set start time
|
||||||
var stopTimeStep = 0; //Time after one step
|
var stopTimeStep = 0; //Time after one step
|
||||||
var timerResetActive = 0; //timer to reset active
|
var timerResetActive = 0; //timer to reset active
|
||||||
|
var timerStoreData = 0; //timer to store data
|
||||||
var steps = 0; //steps taken
|
var steps = 0; //steps taken
|
||||||
var stepsCounted = 0; //active steps counted
|
var stepsCounted = 0; //active steps counted
|
||||||
var active = 0; //x steps in y seconds achieved
|
var active = 0; //x steps in y seconds achieved
|
||||||
var stepGoalPercent = 0; //percentage of step goal
|
var stepGoalPercent = 0; //percentage of step goal
|
||||||
var stepGoalBarLength = 0; //length og progress bar
|
var stepGoalBarLength = 0; //length og progress bar
|
||||||
var lastUpdate = new Date(); //used to reset counted steps on new day
|
var lastUpdate = new Date(); //used to reset counted steps on new day
|
||||||
var width = 45; //width of widget
|
var width = 46; //width of widget
|
||||||
|
|
||||||
//used for statistics and debugging
|
//used for statistics and debugging
|
||||||
var stepsTooShort = 0;
|
var stepsTooShort = 0;
|
||||||
|
|
@ -18,13 +19,33 @@
|
||||||
|
|
||||||
var distance = 0; //distance travelled
|
var distance = 0; //distance travelled
|
||||||
|
|
||||||
|
const s = require('Storage');
|
||||||
const SETTINGS_FILE = 'activepedom.settings.json';
|
const SETTINGS_FILE = 'activepedom.settings.json';
|
||||||
const PEDOMFILE = "activepedom.steps.json";
|
const PEDOMFILE = "activepedom.steps.json";
|
||||||
|
var dataFile;
|
||||||
|
var storeDataInterval = 5*60*1000; //ms
|
||||||
|
|
||||||
let settings;
|
let settings;
|
||||||
//load settings
|
//load settings
|
||||||
function loadSettings() {
|
function loadSettings() {
|
||||||
settings = require('Storage').readJSON(SETTINGS_FILE, 1) || {};
|
settings = s.readJSON(SETTINGS_FILE, 1) || {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function storeData() {
|
||||||
|
now = new Date();
|
||||||
|
month = now.getMonth() + 1;
|
||||||
|
if (month < 10) month = "0" + month;
|
||||||
|
filename = filename = "activepedom-" + now.getFullYear() + month + now.getDate() + ".data";
|
||||||
|
dataFile = s.open(filename,"a");
|
||||||
|
if (dataFile) dataFile.write([
|
||||||
|
now.getTime(),
|
||||||
|
stepsCounted,
|
||||||
|
active,
|
||||||
|
stepsTooShort,
|
||||||
|
stepsTooLong,
|
||||||
|
stepsOutsideTime,
|
||||||
|
].join(",")+"\n");
|
||||||
|
dataFile = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
//return setting
|
//return setting
|
||||||
|
|
@ -77,20 +98,20 @@
|
||||||
|
|
||||||
//Remove step if time between first and second step is too long
|
//Remove step if time between first and second step is too long
|
||||||
if (stepTimeDiff >= setting('cMaxTime')) { //milliseconds
|
if (stepTimeDiff >= setting('cMaxTime')) { //milliseconds
|
||||||
stepsTooLong++; //count steps which are note counted, because time too long
|
stepsTooLong++; //count steps which are not counted, because time too long
|
||||||
steps--;
|
steps--;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Remove step if time between first and second step is too short
|
//Remove step if time between first and second step is too short
|
||||||
if (stepTimeDiff <= setting('cMinTime')) { //milliseconds
|
if (stepTimeDiff <= setting('cMinTime')) { //milliseconds
|
||||||
stepsTooShort++; //count steps which are note counted, because time too short
|
stepsTooShort++; //count steps which are not counted, because time too short
|
||||||
steps--;
|
steps--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Step threshold reached
|
||||||
if (steps >= setting('stepThreshold')) {
|
if (steps >= setting('stepThreshold')) {
|
||||||
if (active == 0) {
|
if (active == 0) {
|
||||||
stepsCounted = stepsCounted + (setting('stepThreshold') -1) ; //count steps needed to reach active status, last step is counted anyway, so treshold -1
|
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
|
stepsOutsideTime = stepsOutsideTime - 10; //substract steps needed to reach active status
|
||||||
}
|
}
|
||||||
active = 1;
|
active = 1;
|
||||||
clearInterval(timerResetActive); //stop timer which resets active
|
clearInterval(timerResetActive); //stop timer which resets active
|
||||||
|
|
@ -109,14 +130,17 @@
|
||||||
|
|
||||||
function draw() {
|
function draw() {
|
||||||
var height = 23; //width is deined globally
|
var height = 23; //width is deined globally
|
||||||
distance = (stepsCounted * setting('stepLength')) / 100 /1000 //distance in km
|
distance = (stepsCounted * setting('stepLength')) / 100 /1000; //distance in km
|
||||||
|
|
||||||
//Check if same day
|
//Check if same day
|
||||||
let date = new Date();
|
let date = new Date();
|
||||||
if (lastUpdate.getDate() == date.getDate()){ //if same day
|
if (lastUpdate.getDate() == date.getDate()){ //if same day
|
||||||
}
|
}
|
||||||
else {
|
else { //different day, set all steps to 0
|
||||||
stepsCounted = 1; //set stepcount to 1
|
stepsCounted = 0;
|
||||||
|
stepsTooShort = 0;
|
||||||
|
stepsTooLong = 0;
|
||||||
|
stepsOutsideTime = 0;
|
||||||
}
|
}
|
||||||
lastUpdate = date;
|
lastUpdate = date;
|
||||||
|
|
||||||
|
|
@ -166,7 +190,7 @@
|
||||||
stepsTooLong : stepsTooLong,
|
stepsTooLong : stepsTooLong,
|
||||||
stepsOutsideTime : stepsOutsideTime
|
stepsOutsideTime : stepsOutsideTime
|
||||||
};
|
};
|
||||||
require("Storage").write(PEDOMFILE,d); //write array to file
|
s.write(PEDOMFILE,d); //write array to file
|
||||||
});
|
});
|
||||||
|
|
||||||
//When Step is registered by firmware
|
//When Step is registered by firmware
|
||||||
|
|
@ -182,8 +206,7 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
//Read data from file and set variables
|
//Read data from file and set variables
|
||||||
let pedomData = require("Storage").readJSON(PEDOMFILE,1);
|
let pedomData = s.readJSON(PEDOMFILE,1);
|
||||||
|
|
||||||
if (pedomData) {
|
if (pedomData) {
|
||||||
if (pedomData.lastUpdate) lastUpdate = new Date(pedomData.lastUpdate);
|
if (pedomData.lastUpdate) lastUpdate = new Date(pedomData.lastUpdate);
|
||||||
stepsCounted = pedomData.stepsToday|0;
|
stepsCounted = pedomData.stepsToday|0;
|
||||||
|
|
@ -191,12 +214,10 @@
|
||||||
stepsTooLong = pedomData.stepsTooLong;
|
stepsTooLong = pedomData.stepsTooLong;
|
||||||
stepsOutsideTime = pedomData.stepsOutsideTime;
|
stepsOutsideTime = pedomData.stepsOutsideTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
pedomdata = 0; //reset pedomdata to save memory
|
pedomdata = 0; //reset pedomdata to save memory
|
||||||
|
|
||||||
setStepSensitivity(setting('stepSensitivity')); //set step sensitivity (80 is standard, 400 is muss less sensitive)
|
setStepSensitivity(setting('stepSensitivity')); //set step sensitivity (80 is standard, 400 is muss less sensitive)
|
||||||
|
timerStoreData = setInterval(storeData, storeDataInterval); //store data regularly
|
||||||
//Add widget
|
//Add widget
|
||||||
WIDGETS["activepedom"]={area:"tl",width:width,draw:draw};
|
WIDGETS["activepedom"]={area:"tl",width:width,draw:draw};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
Loading…
Reference in New Issue