From 51b864438b6bbefc6111f4bf67dbfd34c9361e0e Mon Sep 17 00:00:00 2001 From: Anthony Merlo Date: Fri, 21 Aug 2026 00:19:27 +0100 Subject: [PATCH] fix: use Scripting app API (Health.queryQuantitySamples + HealthUnit) --- scripts/health-sync.js | 53 ++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/scripts/health-sync.js b/scripts/health-sync.js index 0bcd549..b896f04 100644 --- a/scripts/health-sync.js +++ b/scripts/health-sync.js @@ -1,28 +1,36 @@ // Health Sync — reads Apple Health and POSTs to nutrition-mcp server -// Run via Scriptable automation at 9:30am daily +// Run via Scripting app automation at 9:30am daily // Server: http://chronos:9432/ingest // -// Uses Scriptable's Health API: new Health() instance with string units. +// Uses Scripting app's Health API: Health.queryQuantitySamples() with HealthUnit. const SERVER_URL = "http://chronos:9432/ingest"; const API_KEY = "333f09ce904e9cbbe3b578fda393be92869122c7222dbccd"; +// --- Units for each quantity type --- +const U = { + kg: HealthUnit.gram(HealthMetricPrefix.kilo), + mmHg: HealthUnit.millimeterOfMercury(), + bpm: HealthUnit.count().divided(HealthUnit.minute()), + count: HealthUnit.count(), + percent: HealthUnit.percent() +}; + // Read the most recent sample of a type. Returns { value, startDate } or null. async function readLatest(type, unit) { try { - const h = new Health(); - h.setTypeIdentifier(type); - h.setUnit(unit); - h.setLimit(1); - h.setDescendingSorting(); - const samples = await h.quantitySamples(); + const samples = await Health.queryQuantitySamples(type, { + limit: 1, + sortDescriptors: [{ key: "startDate", order: "reverse" }] + }); if (!samples || samples.length === 0) { console.log(`readLatest(${type}): no samples`); return null; } const s = samples[0]; - console.log(`readLatest(${type}): value=${s.value} date=${s.startDate}`); - return { value: s.value, startDate: new Date(s.startDate) }; + const value = s.quantityValue(unit); + console.log(`readLatest(${type}): value=${value} date=${s.startDate}`); + return { value, startDate: s.startDate }; } catch (e) { console.log(`readLatest(${type}): error ${e}`); return null; @@ -34,18 +42,17 @@ async function readTodaySum(type, unit) { try { const start = new Date(); start.setHours(0, 0, 0, 0); - const h = new Health(); - h.setTypeIdentifier(type); - h.setUnit(unit); - const samples = await h.quantitySamples(); + const samples = await Health.queryQuantitySamples(type, { + startDate: start, + endDate: new Date() + }); if (!samples || samples.length === 0) { console.log(`readTodaySum(${type}): no samples`); return null; } let total = 0; for (const s of samples) { - const sd = new Date(s.startDate); - if (sd >= start) total += s.value; + total += s.quantityValue(unit); } console.log(`readTodaySum(${type}): total=${total}`); return total; @@ -70,13 +77,13 @@ async function notify(body) { // --- Read all health metrics --- console.log("=== Health Sync starting ==="); -const weight = await readLatest("bodyMass", "kg"); -const bpSys = await readLatest("bloodPressureSystolic", "mmHg"); -const bpDia = await readLatest("bloodPressureDiastolic", "mmHg"); -const hr = await readLatest("heartRate", "count/min"); -const restingHr = await readLatest("restingHeartRate", "count/min"); -const steps = await readTodaySum("stepCount", "count"); -const spo2 = await readLatest("oxygenSaturation", "%"); +const weight = await readLatest("bodyMass", U.kg); +const bpSys = await readLatest("bloodPressureSystolic", U.mmHg); +const bpDia = await readLatest("bloodPressureDiastolic", U.mmHg); +const hr = await readLatest("heartRate", U.bpm); +const restingHr = await readLatest("restingHeartRate", U.bpm); +const steps = await readTodaySum("stepCount", U.count); +const spo2 = await readLatest("oxygenSaturation", U.percent); console.log(`Results: weight=${weight?.value} bpSys=${bpSys?.value} bpDia=${bpDia?.value} hr=${hr?.value} rhr=${restingHr?.value} steps=${steps} spo2=${spo2?.value}`);