diff --git a/apps/android/ChangeLog b/apps/android/ChangeLog index 4587c0911..f2a0c5b3f 100644 --- a/apps/android/ChangeLog +++ b/apps/android/ChangeLog @@ -29,4 +29,5 @@ 0.28: Navigation messages no longer launch the Maps view unless they're new 0.29: Support for http request xpath return format 0.30: Send firmware and hardware versions on connection - Allow alarm enable/disable \ No newline at end of file + Allow alarm enable/disable +0.31: Implement API for activity fetching diff --git a/apps/android/boot.js b/apps/android/boot.js index 018ea7561..54b1cc8f4 100644 --- a/apps/android/boot.js +++ b/apps/android/boot.js @@ -193,10 +193,37 @@ Bangle.on('HRM',actHRMHandler); actInterval = setInterval(function() { var steps = Bangle.getStepCount(); - gbSend({ t: "act", stp: steps-lastSteps, hrm: lastBPM }); + gbSend({ t: "act", stp: steps-lastSteps, hrm: lastBPM, rt:1 }); lastSteps = steps; }, 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() { event.id="nav"; if (event.instr) { diff --git a/apps/android/metadata.json b/apps/android/metadata.json index e875c2072..8d65d32e3 100644 --- a/apps/android/metadata.json +++ b/apps/android/metadata.json @@ -2,7 +2,7 @@ "id": "android", "name": "Android Integration", "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.", "icon": "app.png", "tags": "tool,system,messages,notifications,gadgetbridge", diff --git a/apps/gbridge/PROTOCOL.md b/apps/gbridge/PROTOCOL.md index 7191ca0b1..cb86a1314 100644 --- a/apps/gbridge/PROTOCOL.md +++ b/apps/gbridge/PROTOCOL.md @@ -59,6 +59,26 @@ Send a response to a notification from phone * n can be one of "dismiss", "dismiss all", "open", "mute", "reply" * 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 ## show notification @@ -177,3 +197,14 @@ n is the intensity * hum is the humidity * txt is the weather condition * loc is the location + +## fetch activity data + +```json +{ + "t": "actfetch", + "ts": 1692226800000 +} +``` + +* `ts` is the start timestamp, in milliseconds since the unix epoch diff --git a/apps/gbridge/widget.js b/apps/gbridge/widget.js index 3b5f2c780..6f4b945a5 100644 --- a/apps/gbridge/widget.js +++ b/apps/gbridge/widget.js @@ -263,7 +263,7 @@ function sendActivity(hrm) { var steps = currentSteps - lastSentSteps; lastSentSteps = currentSteps; - gbSend({ t: "act", stp: steps, hrm:hrm }); + gbSend({ t: "act", stp: steps, hrm:hrm, rt:1 }); } // Battery monitor diff --git a/apps/health/ChangeLog b/apps/health/ChangeLog index da68bc0e7..6bc15be83 100644 --- a/apps/health/ChangeLog +++ b/apps/health/ChangeLog @@ -25,4 +25,5 @@ 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 movement graph in app is now an average, not sum - fix 11pm slot for daily HRM \ No newline at end of file + fix 11pm slot for daily HRM +0.26: Implement API for activity fetching diff --git a/apps/health/lib.js b/apps/health/lib.js index 7ecbd5bff..8f3cc800e 100644 --- a/apps/health/lib.js +++ b/apps/health/lib.js @@ -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 } -} +}; + +// 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 exports.readDailySummaries = function(d, cb) { diff --git a/apps/health/metadata.json b/apps/health/metadata.json index 5ff3bb3a0..10c8268cb 100644 --- a/apps/health/metadata.json +++ b/apps/health/metadata.json @@ -2,7 +2,7 @@ "id": "health", "name": "Health Tracking", "shortName": "Health", - "version": "0.25", + "version": "0.26", "description": "Logs health data and provides an app to view it", "icon": "app.png", "tags": "tool,system,health",