Merge pull request #2442 from myxor/health_step_goal_notification

Health: Step goal reached notification
pull/2467/head
Gordon Williams 2023-01-06 15:11:20 +00:00 committed by GitHub
commit 059a2e7af7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 43 additions and 8 deletions

View File

@ -17,3 +17,4 @@
0.16: Code tidyup, add back button in top left of health app graphs 0.16: Code tidyup, add back button in top left of health app graphs
0.17: Add automatic translation of bar chart labels 0.17: Add automatic translation of bar chart labels
0.18: Show step goal in daily step chart 0.18: Show step goal in daily step chart
0.19: Can show notification when daily step goal is reached

View File

@ -25,7 +25,8 @@ Stores:
* **3 Min** - Turn HRM on every 3 minutes (for each heath entry) and turn it off after 1 minute, or when a good reading is found * **3 Min** - Turn HRM on every 3 minutes (for each heath entry) and turn it off after 1 minute, or when a good reading is found
* **10 Min** - Turn HRM on every 10 minutes (for each heath entry) and turn it off after 2 minutes, or when a good reading is found * **10 Min** - Turn HRM on every 10 minutes (for each heath entry) and turn it off after 2 minutes, or when a good reading is found
* **Always** - Keep HRM on all the time (more accurate recording, but reduces battery life to ~36 hours) * **Always** - Keep HRM on all the time (more accurate recording, but reduces battery life to ~36 hours)
* **Daily Step Goal** - Default 10000, daily step goal for pedometer apps to use * **Daily Step Goal** - Default 10000, daily step goal for pedometer apps to use and for the step goal notification
* **Step Goal Notification** - True if you want a notification when the daily step goal is reached
## Technical Info ## Technical Info

View File

@ -36,6 +36,10 @@ Bangle.on("health", health => {
const DB_HEADER_LEN = 8; const DB_HEADER_LEN = 8;
const DB_FILE_LEN = DB_HEADER_LEN + DB_RECORDS_PER_MONTH*DB_RECORD_LEN; const DB_FILE_LEN = DB_HEADER_LEN + DB_RECORDS_PER_MONTH*DB_RECORD_LEN;
if (health && health.steps > 0) {
handleStepGoalNotification();
}
function getRecordFN(d) { function getRecordFN(d) {
return "health-"+d.getFullYear()+"-"+(d.getMonth()+1)+".raw"; return "health-"+d.getFullYear()+"-"+(d.getMonth()+1)+".raw";
} }
@ -92,3 +96,21 @@ Bangle.on("health", health => {
health.movement /= health.movCnt; health.movement /= health.movCnt;
require("Storage").write(fn, getRecordData(health), sumPos, DB_FILE_LEN); require("Storage").write(fn, getRecordData(health), sumPos, DB_FILE_LEN);
}); });
function handleStepGoalNotification() {
var settings = require("Storage").readJSON("health.json",1)||{};
const steps = Bangle.getHealthStatus("day").steps;
if (settings.stepGoalNotification && settings.stepGoal > 0 && steps >= settings.stepGoal) {
const now = new Date(Date.now()).toISOString().split('T')[0]; // yyyy-mm-dd
if (!settings.stepGoalNotificationDate || settings.stepGoalNotificationDate < now) { // notification not yet shown today?
Bangle.buzz(200, 0.5);
require("notify").show({
title : /*LANG*/ settings.stepGoal + " steps",
body : /*LANG*/ "You reached your step goal!",
icon : atob("DAyBABmD6BaBMAsA8BCBCBCBCA8AAA==")
});
settings.stepGoalNotificationDate = now;
require("Storage").writeJSON("health.json", settings);
}
}
}

View File

@ -1,4 +1,5 @@
(function(){var a=0|(require("Storage").readJSON("health.json",1)||{}).hrm;if(1==a||2==a){function f(){Bangle.setHRMPower(1,"health");setTimeout(()=>Bangle.setHRMPower(0,"health"),6E4*a);if(1==a)for(var b=1;2>=b;b++)setTimeout(()=>{Bangle.setHRMPower(1,"health");setTimeout(()=>{Bangle.setHRMPower(0,"health")},2E5*b+6E4)},2E5*b)}Bangle.on("health",f);Bangle.on("HRM",b=>{80<b.confidence&&Bangle.setHRMPower(0,"health")});Bangle.getHealthStatus().bpmConfidence||f()}else Bangle.setHRMPower(0!= function l(){var a=require("Storage").readJSON("health.json",1)||{},d=Bangle.getHealthStatus("day").steps;a.stepGoalNotification&&0<a.stepGoal&&d>=a.stepGoal&&(d=(new Date(Date.now())).toISOString().split("T")[0],!a.stepGoalNotificationDate||a.stepGoalNotificationDate<d)&&(Bangle.buzz(200,.5),require("notify").show({title:"8000 steps",body:"You reached your step goal!",icon:atob("DAyBABmD6BaBMAsA8BCBCBCBCA8AAA==")}),a.stepGoalNotificationDate=d,require("Storage").writeJSON("health.json",
a,"health")})();Bangle.on("health",a=>{function f(c){return String.fromCharCode(c.steps>>8,c.steps&255,c.bpm,Math.min(c.movement/8,255))}var b=new Date(Date.now()-59E4),e=function(c){return 145*(c.getDate()-1)+6*c.getHours()+(0|6*c.getMinutes()/60)}(b);b=function(c){return"health-"+c.getFullYear()+"-"+(c.getMonth()+1)+".raw"}(b);var g=require("Storage").read(b);if(g){var d=g.substr(8+4*e,4);if("\u00ff\u00ff\u00ff\u00ff"!=d){print("HEALTH ERR: Already written!");return}}else require("Storage").write(b, a))}(function(){var a=0|(require("Storage").readJSON("health.json",1)||{}).hrm;if(1==a||2==a){var d=function(){Bangle.setHRMPower(1,"health");setTimeout(function(){return Bangle.setHRMPower(0,"health")},6E4*a);if(1==a)for(var b=1;2>=b;b++)setTimeout(function(){Bangle.setHRMPower(1,"health");setTimeout(function(){Bangle.setHRMPower(0,"health")},2E5*b+6E4)},2E5*b)};Bangle.on("health",d);Bangle.on("HRM",function(b){80<b.confidence&&Bangle.setHRMPower(0,"health")});Bangle.getHealthStatus().bpmConfidence||
"HEALTH1\x00",0,17988);var h=8+4*e;require("Storage").write(b,f(a),h,17988);if(143==e%145)if(e=h+4,"\u00ff\u00ff\u00ff\u00ff"!=g.substr(e,4))print("HEALTH ERR: Daily summary already written!");else{a={steps:0,bpm:0,movement:0,movCnt:0,bpmCnt:0};for(var k=0;144>k;k++)d=g.substr(h,4),"\u00ff\u00ff\u00ff\u00ff"!=d&&(a.steps+=(d.charCodeAt(0)<<8)+d.charCodeAt(1),a.movement+=d.charCodeAt(2),a.movCnt++,d=d.charCodeAt(2),a.bpm+=d,d&&a.bpmCnt++),h-=4;a.bpmCnt&&(a.bpm/=a.bpmCnt);a.movCnt&&(a.movement/=a.movCnt); d()}else Bangle.setHRMPower(0!=a,"health")})();Bangle.on("health",function(a){function d(c){return String.fromCharCode(c.steps>>8,c.steps&255,c.bpm,Math.min(c.movement/8,255))}var b=new Date(Date.now()-59E4);a&&0<a.steps&&l();var f=function(c){return 145*(c.getDate()-1)+6*c.getHours()+(0|6*c.getMinutes()/60)}(b);b=function(c){return"health-"+c.getFullYear()+"-"+(c.getMonth()+1)+".raw"}(b);var g=require("Storage").read(b);if(g){var e=g.substr(8+4*f,4);if("\u00ff\u00ff\u00ff\u00ff"!=e){print("HEALTH ERR: Already written!");
require("Storage").write(b,f(a),e,17988)}}) return}}else require("Storage").write(b,"HEALTH1\x00",0,17988);var h=8+4*f;require("Storage").write(b,d(a),h,17988);if(143==f%145)if(f=h+4,"\u00ff\u00ff\u00ff\u00ff"!=g.substr(f,4))print("HEALTH ERR: Daily summary already written!");else{a={steps:0,bpm:0,movement:0,movCnt:0,bpmCnt:0};for(var k=0;144>k;k++)e=g.substr(h,4),"\u00ff\u00ff\u00ff\u00ff"!=e&&(a.steps+=(e.charCodeAt(0)<<8)+e.charCodeAt(1),a.movement+=e.charCodeAt(2),a.movCnt++,e=e.charCodeAt(2),a.bpm+=e,e&&a.bpmCnt++),h-=4;a.bpmCnt&&(a.bpm/=
a.bpmCnt);a.movCnt&&(a.movement/=a.movCnt);require("Storage").write(b,d(a),f,17988)}})

View File

@ -2,7 +2,7 @@
"id": "health", "id": "health",
"name": "Health Tracking", "name": "Health Tracking",
"shortName": "Health", "shortName": "Health",
"version": "0.18", "version": "0.19",
"description": "Logs health data and provides an app to view it", "description": "Logs health data and provides an app to view it",
"icon": "app.png", "icon": "app.png",
"tags": "tool,system,health", "tags": "tool,system,health",
@ -16,5 +16,6 @@
{"name":"health","url":"lib.min.js"}, {"name":"health","url":"lib.min.js"},
{"name":"health.settings.js","url":"settings.js"} {"name":"health.settings.js","url":"settings.js"}
], ],
"data": [{"name":"health.json"}] "data": [{"name":"health.json"}],
"dependencies": {"notify":"type"}
} }

View File

@ -1,7 +1,8 @@
(function (back) { (function (back) {
var settings = Object.assign({ var settings = Object.assign({
hrm: 0, hrm: 0,
stepGoal: 10000 stepGoal: 10000,
stepGoalNotification: false
}, require("Storage").readJSON("health.json", true) || {}); }, require("Storage").readJSON("health.json", true) || {});
E.showMenu({ E.showMenu({
@ -34,6 +35,14 @@
settings.stepGoal = v; settings.stepGoal = v;
setSettings(settings); setSettings(settings);
} }
},
/*LANG*/"Step Goal Notification": {
value: "stepGoalNotification" in settings ? settings.stepGoalNotification : false,
format: () => (settings.stepGoalNotification ? 'Yes' : 'No'),
onchange: () => {
settings.stepGoalNotification = !settings.stepGoalNotification;
setSettings();
}
} }
}); });