mirror of https://github.com/espruino/BangleApps
Implement API for activity fetching
parent
57a9dd027f
commit
89737153a0
|
@ -29,4 +29,5 @@
|
||||||
0.28: Navigation messages no longer launch the Maps view unless they're new
|
0.28: Navigation messages no longer launch the Maps view unless they're new
|
||||||
0.29: Support for http request xpath return format
|
0.29: Support for http request xpath return format
|
||||||
0.30: Send firmware and hardware versions on connection
|
0.30: Send firmware and hardware versions on connection
|
||||||
Allow alarm enable/disable
|
Allow alarm enable/disable
|
||||||
|
0.31: Implement API for activity fetching
|
||||||
|
|
|
@ -193,10 +193,37 @@
|
||||||
Bangle.on('HRM',actHRMHandler);
|
Bangle.on('HRM',actHRMHandler);
|
||||||
actInterval = setInterval(function() {
|
actInterval = setInterval(function() {
|
||||||
var steps = Bangle.getStepCount();
|
var steps = Bangle.getStepCount();
|
||||||
gbSend({ t: "act", stp: steps-lastSteps, hrm: lastBPM });
|
gbSend({ t: "act", stp: steps-lastSteps, hrm: lastBPM, rt:1 });
|
||||||
lastSteps = steps;
|
lastSteps = steps;
|
||||||
}, event.int*1000);
|
}, event.int*1000);
|
||||||
},
|
},
|
||||||
|
// {t:"actfetch", ts:long}
|
||||||
|
"actfetch": function() {
|
||||||
|
gbSend({t: "actfetch", state: "start"});
|
||||||
|
var actCount = 0;
|
||||||
|
var actCb = function(r) {
|
||||||
|
// The health lib saves the samples at the start of the 10-minute block
|
||||||
|
// However, GB expects them at the end of the block, so let's offset them
|
||||||
|
// here to keep a consistent API in the health lib
|
||||||
|
var sampleTs = r.date.getTime() + 600000;
|
||||||
|
if (sampleTs >= event.ts) {
|
||||||
|
gbSend({
|
||||||
|
t: "act",
|
||||||
|
ts: sampleTs,
|
||||||
|
stp: r.steps,
|
||||||
|
hrm: r.bpm,
|
||||||
|
mov: r.movement
|
||||||
|
});
|
||||||
|
actCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (event.ts != 0) {
|
||||||
|
require("health").readAllRecordsSince(new Date(event.ts - 600000), actCb);
|
||||||
|
} else {
|
||||||
|
require("health").readFullDatabase(actCb);
|
||||||
|
}
|
||||||
|
gbSend({t: "actfetch", state: "end", count: actCount});
|
||||||
|
},
|
||||||
"nav": function() {
|
"nav": function() {
|
||||||
event.id="nav";
|
event.id="nav";
|
||||||
if (event.instr) {
|
if (event.instr) {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "android",
|
"id": "android",
|
||||||
"name": "Android Integration",
|
"name": "Android Integration",
|
||||||
"shortName": "Android",
|
"shortName": "Android",
|
||||||
"version": "0.30",
|
"version": "0.31",
|
||||||
"description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.",
|
"description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"tags": "tool,system,messages,notifications,gadgetbridge",
|
"tags": "tool,system,messages,notifications,gadgetbridge",
|
||||||
|
|
|
@ -59,6 +59,26 @@ Send a response to a notification from phone
|
||||||
* n can be one of "dismiss", "dismiss all", "open", "mute", "reply"
|
* n can be one of "dismiss", "dismiss all", "open", "mute", "reply"
|
||||||
* id, tel and message are optional
|
* id, tel and message are optional
|
||||||
|
|
||||||
|
## activity data
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"t": "act",
|
||||||
|
"ts": 1692226800000,
|
||||||
|
"stp": 26,
|
||||||
|
"hrm": 70,
|
||||||
|
"mov": 10,
|
||||||
|
"rt": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* `ts` is the sample timestamp, in milliseconds since the unix epoch
|
||||||
|
* `stp` is the number of steps
|
||||||
|
* `hrm` is heart rate, in bpm
|
||||||
|
* `mov` is the movement intensity (todo: range?)
|
||||||
|
* `rt` whether it is a real-time sample
|
||||||
|
|
||||||
|
|
||||||
# Phone -> Watch
|
# Phone -> Watch
|
||||||
|
|
||||||
## show notification
|
## show notification
|
||||||
|
@ -177,3 +197,14 @@ n is the intensity
|
||||||
* hum is the humidity
|
* hum is the humidity
|
||||||
* txt is the weather condition
|
* txt is the weather condition
|
||||||
* loc is the location
|
* loc is the location
|
||||||
|
|
||||||
|
## fetch activity data
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"t": "actfetch",
|
||||||
|
"ts": 1692226800000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* `ts` is the start timestamp, in milliseconds since the unix epoch
|
||||||
|
|
|
@ -263,7 +263,7 @@
|
||||||
function sendActivity(hrm) {
|
function sendActivity(hrm) {
|
||||||
var steps = currentSteps - lastSentSteps;
|
var steps = currentSteps - lastSentSteps;
|
||||||
lastSentSteps = currentSteps;
|
lastSentSteps = currentSteps;
|
||||||
gbSend({ t: "act", stp: steps, hrm:hrm });
|
gbSend({ t: "act", stp: steps, hrm:hrm, rt:1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Battery monitor
|
// Battery monitor
|
||||||
|
|
|
@ -25,4 +25,5 @@
|
||||||
0.24: Correct daily health summary for movement (some logic errors resulted in garbage data being written)
|
0.24: Correct daily health summary for movement (some logic errors resulted in garbage data being written)
|
||||||
0.25: lib.read* methods now return correctly scaled movement
|
0.25: lib.read* methods now return correctly scaled movement
|
||||||
movement graph in app is now an average, not sum
|
movement graph in app is now an average, not sum
|
||||||
fix 11pm slot for daily HRM
|
fix 11pm slot for daily HRM
|
||||||
|
0.26: Implement API for activity fetching
|
||||||
|
|
|
@ -37,7 +37,36 @@ exports.readAllRecords = function(d, cb) {
|
||||||
}
|
}
|
||||||
idx += DB_RECORD_LEN; // +1 because we have an extra record with totals for the end of the day
|
idx += DB_RECORD_LEN; // +1 because we have an extra record with totals for the end of the day
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// Read the entire database. There is no guarantee that the months are read in order.
|
||||||
|
exports.readFullDatabase = function(cb) {
|
||||||
|
require("Storage").list(/health-[0-9]+-[0-9]+.raw/).forEach(val => {
|
||||||
|
console.log(val);
|
||||||
|
var parts = val.split('-');
|
||||||
|
var y = parseInt(parts[1]);
|
||||||
|
var mo = parseInt(parts[2].replace('.raw', ''));
|
||||||
|
|
||||||
|
exports.readAllRecords(new Date(y, mo, 1), (r) => {
|
||||||
|
r.date = new Date(y, mo, r.day, r.hr, r.min);
|
||||||
|
cb(r);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Read all records per day, until the current time.
|
||||||
|
// There may be some records for the day of the timestamp previous to the timestamp
|
||||||
|
exports.readAllRecordsSince = function(d, cb) {
|
||||||
|
var currentDate = new Date().getTime();
|
||||||
|
var di = d;
|
||||||
|
while (di.getTime() <= currentDate) {
|
||||||
|
exports.readDay(di, (r) => {
|
||||||
|
r.date = new Date(di.getFullYear(), di.getMonth(), di.getDate(), r.hr, r.min);
|
||||||
|
cb(r);
|
||||||
|
});
|
||||||
|
di.setDate(di.getDate() + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Read daily summaries from the given month
|
// Read daily summaries from the given month
|
||||||
exports.readDailySummaries = function(d, cb) {
|
exports.readDailySummaries = function(d, cb) {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "health",
|
"id": "health",
|
||||||
"name": "Health Tracking",
|
"name": "Health Tracking",
|
||||||
"shortName": "Health",
|
"shortName": "Health",
|
||||||
"version": "0.25",
|
"version": "0.26",
|
||||||
"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",
|
||||||
|
|
Loading…
Reference in New Issue