health: Added graphs for Temperature and Battery, also reduced duplication in graph code
parent
f706ba79f1
commit
95d8b54803
|
|
@ -33,3 +33,4 @@
|
||||||
0.29: Minor code improvements
|
0.29: Minor code improvements
|
||||||
0.30: Minor code improvements
|
0.30: Minor code improvements
|
||||||
0.31: Add support for new health format (storing more data)
|
0.31: Add support for new health format (storing more data)
|
||||||
|
Added graphs for Temperature and Battery
|
||||||
|
|
@ -79,7 +79,8 @@ require("health").readDay(d, cb)
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
* More features in app:
|
* More features in app:
|
||||||
* Viewing stored altitude/battery/temperature/bpm min/max graphs
|
* Viewing stored altitude/bpm min/max graphs
|
||||||
|
* Currently we only graph per hour but we have 10 min data - should it be shown?
|
||||||
* Pie chart to show percent of time in each activity
|
* Pie chart to show percent of time in each activity
|
||||||
* Calendar view showing steps per day
|
* Calendar view showing steps per day
|
||||||
* Yearly view
|
* Yearly view
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ function menuMain() {
|
||||||
/*LANG*/"Step Counting": () => menuStepCount(),
|
/*LANG*/"Step Counting": () => menuStepCount(),
|
||||||
/*LANG*/"Movement": () => menuMovement(),
|
/*LANG*/"Movement": () => menuMovement(),
|
||||||
/*LANG*/"Heart Rate": () => menuHRM(),
|
/*LANG*/"Heart Rate": () => menuHRM(),
|
||||||
|
/*LANG*/"Battery": () => menuBattery(),
|
||||||
|
/*LANG*/"Temperature": () => menuTemperature(),
|
||||||
/*LANG*/"Settings": () => eval(require("Storage").read("health.settings.js"))(()=>{loadSettings();menuMain();})
|
/*LANG*/"Settings": () => eval(require("Storage").read("health.settings.js"))(()=>{loadSettings();menuMain();})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -16,8 +18,11 @@ function menuStepCount() {
|
||||||
const menu = {
|
const menu = {
|
||||||
"": { title:/*LANG*/"Steps" },
|
"": { title:/*LANG*/"Steps" },
|
||||||
/*LANG*/"< Back": () => menuMain(),
|
/*LANG*/"< Back": () => menuMain(),
|
||||||
/*LANG*/"per hour": () => stepsPerHour(menuStepCount),
|
/*LANG*/"per hour": () => showGraph({id:"stepsPerHour",range:"hour",field:"steps", back:menuStepCount}),
|
||||||
/*LANG*/"per day": () => stepsPerDay(menuStepCount)
|
/*LANG*/"per day": () => {
|
||||||
|
showGraph({id:"stepsPerHour",range:"day",field:"steps", back:menuStepCount})
|
||||||
|
drawHorizontalLine(settings.stepGoal);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
if (myprofile.strideLength) {
|
if (myprofile.strideLength) {
|
||||||
menu[/*LANG*/"distance"] = () => menuDistance();
|
menu[/*LANG*/"distance"] = () => menuDistance();
|
||||||
|
|
@ -31,8 +36,11 @@ function menuDistance() {
|
||||||
E.showMenu({
|
E.showMenu({
|
||||||
"": { title:/*LANG*/"Distance" },
|
"": { title:/*LANG*/"Distance" },
|
||||||
/*LANG*/"< Back": () => menuStepCount(),
|
/*LANG*/"< Back": () => menuStepCount(),
|
||||||
/*LANG*/"per hour": () => stepsPerHour(menuDistance, distMult),
|
/*LANG*/"per hour": () => showGraph({id:"stepsPerHour",range:"hour",field:"steps",mult:distMult, back:menuDistance}),
|
||||||
/*LANG*/"per day": () => stepsPerDay(menuDistance, distMult)
|
/*LANG*/"per day": () => {
|
||||||
|
showGraph({id:"stepsPerDay",range:"day",field:"steps",mult:distMult, back:menuDistance})
|
||||||
|
drawHorizontalLine(settings.stepGoal * (mult || 1));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,8 +48,8 @@ function menuMovement() {
|
||||||
E.showMenu({
|
E.showMenu({
|
||||||
"": { title:/*LANG*/"Movement" },
|
"": { title:/*LANG*/"Movement" },
|
||||||
/*LANG*/"< Back": () => menuMain(),
|
/*LANG*/"< Back": () => menuMain(),
|
||||||
/*LANG*/"per hour": () => movementPerHour(),
|
/*LANG*/"per hour": () => showGraph({id:"movementPerHour",range:"hour",field:"movement",average:true,back:menuMovement}),
|
||||||
/*LANG*/"per day": () => movementPerDay(),
|
/*LANG*/"per day": () => showGraph({id:"movementPerDay",range:"day",field:"movement",average:true,back:menuMovement}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,96 +57,76 @@ function menuHRM() {
|
||||||
E.showMenu({
|
E.showMenu({
|
||||||
"": { title:/*LANG*/"Heart Rate" },
|
"": { title:/*LANG*/"Heart Rate" },
|
||||||
/*LANG*/"< Back": () => menuMain(),
|
/*LANG*/"< Back": () => menuMain(),
|
||||||
/*LANG*/"per hour": () => hrmPerHour(),
|
/*LANG*/"per hour": () => showGraph({id:"hrmPerHour",range:"hour",field:"bpm",ignoreZero:true, average:true,back:menuHRM}),
|
||||||
/*LANG*/"per day": () => hrmPerDay(),
|
/*LANG*/"per day": () => showGraph({id:"hrmPerDay",range:"day",field:"bpm",ignoreZero:true, average:true,back:menuHRM}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function stepsPerHour(back, mult) {
|
function menuBattery() {
|
||||||
E.showMessage(/*LANG*/"Loading...");
|
E.showMenu({
|
||||||
current_selection = "stepsPerHour";
|
"": { title:/*LANG*/"Battery" },
|
||||||
var data = new Uint16Array(24);
|
/*LANG*/"< Back": () => menuMain(),
|
||||||
require("health").readDay(new Date(), h=>data[h.hr]+=h.steps);
|
/*LANG*/"per hour": () => showGraph({id:"batPerHour",range:"hour",field:"battery",average:true,back:menuBattery}),
|
||||||
if (mult !== undefined) {
|
/*LANG*/"per day": () => showGraph({id:"batPerDay",range:"day",field:"battery",average:true,back:menuBattery}),
|
||||||
// Calculate distance from steps
|
});
|
||||||
data.forEach((d, i) => data[i] = d*mult+0.5);
|
|
||||||
}
|
|
||||||
setButton(back, mult);
|
|
||||||
barChart(/*LANG*/"HOUR", data, mult);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function stepsPerDay(back, mult) {
|
function menuTemperature() {
|
||||||
|
E.showMenu({
|
||||||
|
"": { title:/*LANG*/"Temperature" },
|
||||||
|
/*LANG*/"< Back": () => menuMain(),
|
||||||
|
/*LANG*/"per hour": () => showGraph({id:"batPerHour",range:"hour",field:"temperature",average:true,back:menuTemperature}),
|
||||||
|
/*LANG*/"per day": () => showGraph({id:"batPerDay",range:"day",field:"temperature",average:true,back:menuTemperature}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Display a graph. Options are:
|
||||||
|
|
||||||
|
{
|
||||||
|
range: "day"/"hour"
|
||||||
|
id: "stepsPerHour" // id of graph
|
||||||
|
field: "steps" // field name
|
||||||
|
mult: 1.0, // optional multiplier
|
||||||
|
ignoreZero: bool, // if set, ignore record that were 0 in average
|
||||||
|
average: bool, // if set, average records (ignoring)
|
||||||
|
back: fn() // callback for back button
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
function showGraph(options) {
|
||||||
E.showMessage(/*LANG*/"Loading...");
|
E.showMessage(/*LANG*/"Loading...");
|
||||||
current_selection = "stepsPerDay";
|
current_selection = options.id;
|
||||||
|
var data,cnt,title;
|
||||||
|
if (options.range=="hour") {
|
||||||
|
title = /*LANG*/"HOUR";
|
||||||
|
data = new Uint16Array(24);
|
||||||
|
cnt = new Uint8Array(24);
|
||||||
|
require("health").readDay(new Date(), h=>{
|
||||||
|
data[h.hr]+=h[options.field];
|
||||||
|
if (!options.ignoreZero || h[options.field]) cnt[h.hr]++;
|
||||||
|
});
|
||||||
|
} else if (options.range=="day") {
|
||||||
|
title = /*LANG*/"DAY";
|
||||||
var data = new Uint16Array(32);
|
var data = new Uint16Array(32);
|
||||||
require("health").readDailySummaries(new Date(), h=>data[h.day]+=h.steps);
|
var cnt = new Uint8Array(32);
|
||||||
|
require("health").readDailySummaries(new Date(), h=>{
|
||||||
|
data[h.day]+=h[options.field];
|
||||||
|
if (!options.ignoreZero || h[options.field]) cnt[h.day]++;
|
||||||
|
});
|
||||||
// Include data for today
|
// Include data for today
|
||||||
if (data[(new Date()).getDate()] === 0) {
|
var day = (new Date()).getDate();
|
||||||
data[(new Date()).getDate()] = Bangle.getHealthStatus("day").steps;
|
if (data[day] === 0) {
|
||||||
|
data[day] = Bangle.getHealthStatus("day")[options.field];
|
||||||
|
if (!options.ignoreZero || data[day]) cnt[day]++;
|
||||||
}
|
}
|
||||||
if (mult !== undefined) {
|
} else throw new Error("Unknown range");
|
||||||
// Calculate distance from steps
|
if (options.average)
|
||||||
data.forEach((d, i) => data[i] = d*mult+0.5);
|
data.forEach((d,i)=>data[i] = d/cnt[i]+0.5);
|
||||||
|
if (options.mult !== undefined) { // Calculate distance from steps
|
||||||
|
data.forEach((d, i) => data[i] = d*options.mult+0.5);
|
||||||
}
|
}
|
||||||
setButton(back, mult);
|
setButton(options.back, options.mult);
|
||||||
barChart(/*LANG*/"DAY", data, mult);
|
barChart(title, data, options.mult);
|
||||||
drawHorizontalLine(settings.stepGoal * (mult || 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
function hrmPerHour() {
|
|
||||||
E.showMessage(/*LANG*/"Loading...");
|
|
||||||
current_selection = "hrmPerHour";
|
|
||||||
var data = new Uint16Array(24);
|
|
||||||
var cnt = new Uint8Array(24);
|
|
||||||
require("health").readDay(new Date(), h=>{
|
|
||||||
data[h.hr]+=h.bpm;
|
|
||||||
if (h.bpm) cnt[h.hr]++;
|
|
||||||
});
|
|
||||||
data.forEach((d,i)=>data[i] = d/cnt[i]+0.5);
|
|
||||||
setButton(menuHRM);
|
|
||||||
barChart(/*LANG*/"HOUR", data);
|
|
||||||
}
|
|
||||||
|
|
||||||
function hrmPerDay() {
|
|
||||||
E.showMessage(/*LANG*/"Loading...");
|
|
||||||
current_selection = "hrmPerDay";
|
|
||||||
var data = new Uint16Array(32);
|
|
||||||
var cnt = new Uint8Array(32);
|
|
||||||
require("health").readDailySummaries(new Date(), h=>{
|
|
||||||
data[h.day]+=h.bpm;
|
|
||||||
if (h.bpm) cnt[h.day]++;
|
|
||||||
});
|
|
||||||
data.forEach((d,i)=>data[i] = d/cnt[i]+0.5);
|
|
||||||
setButton(menuHRM);
|
|
||||||
barChart(/*LANG*/"DAY", data);
|
|
||||||
}
|
|
||||||
|
|
||||||
function movementPerHour() {
|
|
||||||
E.showMessage(/*LANG*/"Loading...");
|
|
||||||
current_selection = "movementPerHour";
|
|
||||||
var data = new Uint16Array(24);
|
|
||||||
var cnt = new Uint8Array(24);
|
|
||||||
require("health").readDay(new Date(), h=>{
|
|
||||||
data[h.hr]+=h.movement;
|
|
||||||
cnt[h.hr]++;
|
|
||||||
});
|
|
||||||
data.forEach((d,i)=>data[i] = d/cnt[i]+0.5);
|
|
||||||
setButton(menuMovement);
|
|
||||||
barChart(/*LANG*/"HOUR", data);
|
|
||||||
}
|
|
||||||
|
|
||||||
function movementPerDay() {
|
|
||||||
E.showMessage(/*LANG*/"Loading...");
|
|
||||||
current_selection = "movementPerDay";
|
|
||||||
var data = new Uint16Array(32);
|
|
||||||
var cnt = new Uint8Array(32);
|
|
||||||
require("health").readDailySummaries(new Date(), h=>{
|
|
||||||
data[h.day]+=h.movement;
|
|
||||||
cnt[h.day]++;
|
|
||||||
});
|
|
||||||
data.forEach((d,i)=>data[i] = d/cnt[i]+0.5);
|
|
||||||
setButton(menuMovement);
|
|
||||||
barChart(/*LANG*/"DAY", data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bar Chart Code
|
// Bar Chart Code
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue