fix: use Scripting app API (Health.queryQuantitySamples + HealthUnit)

This commit is contained in:
Anthony Merlo 2026-08-21 00:19:27 +01:00
parent e01c0b92e3
commit 51b864438b

View file

@ -1,28 +1,36 @@
// Health Sync — reads Apple Health and POSTs to nutrition-mcp server // 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 // 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 SERVER_URL = "http://chronos:9432/ingest";
const API_KEY = "333f09ce904e9cbbe3b578fda393be92869122c7222dbccd"; 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. // Read the most recent sample of a type. Returns { value, startDate } or null.
async function readLatest(type, unit) { async function readLatest(type, unit) {
try { try {
const h = new Health(); const samples = await Health.queryQuantitySamples(type, {
h.setTypeIdentifier(type); limit: 1,
h.setUnit(unit); sortDescriptors: [{ key: "startDate", order: "reverse" }]
h.setLimit(1); });
h.setDescendingSorting();
const samples = await h.quantitySamples();
if (!samples || samples.length === 0) { if (!samples || samples.length === 0) {
console.log(`readLatest(${type}): no samples`); console.log(`readLatest(${type}): no samples`);
return null; return null;
} }
const s = samples[0]; const s = samples[0];
console.log(`readLatest(${type}): value=${s.value} date=${s.startDate}`); const value = s.quantityValue(unit);
return { value: s.value, startDate: new Date(s.startDate) }; console.log(`readLatest(${type}): value=${value} date=${s.startDate}`);
return { value, startDate: s.startDate };
} catch (e) { } catch (e) {
console.log(`readLatest(${type}): error ${e}`); console.log(`readLatest(${type}): error ${e}`);
return null; return null;
@ -34,18 +42,17 @@ async function readTodaySum(type, unit) {
try { try {
const start = new Date(); const start = new Date();
start.setHours(0, 0, 0, 0); start.setHours(0, 0, 0, 0);
const h = new Health(); const samples = await Health.queryQuantitySamples(type, {
h.setTypeIdentifier(type); startDate: start,
h.setUnit(unit); endDate: new Date()
const samples = await h.quantitySamples(); });
if (!samples || samples.length === 0) { if (!samples || samples.length === 0) {
console.log(`readTodaySum(${type}): no samples`); console.log(`readTodaySum(${type}): no samples`);
return null; return null;
} }
let total = 0; let total = 0;
for (const s of samples) { for (const s of samples) {
const sd = new Date(s.startDate); total += s.quantityValue(unit);
if (sd >= start) total += s.value;
} }
console.log(`readTodaySum(${type}): total=${total}`); console.log(`readTodaySum(${type}): total=${total}`);
return total; return total;
@ -70,13 +77,13 @@ async function notify(body) {
// --- Read all health metrics --- // --- Read all health metrics ---
console.log("=== Health Sync starting ==="); console.log("=== Health Sync starting ===");
const weight = await readLatest("bodyMass", "kg"); const weight = await readLatest("bodyMass", U.kg);
const bpSys = await readLatest("bloodPressureSystolic", "mmHg"); const bpSys = await readLatest("bloodPressureSystolic", U.mmHg);
const bpDia = await readLatest("bloodPressureDiastolic", "mmHg"); const bpDia = await readLatest("bloodPressureDiastolic", U.mmHg);
const hr = await readLatest("heartRate", "count/min"); const hr = await readLatest("heartRate", U.bpm);
const restingHr = await readLatest("restingHeartRate", "count/min"); const restingHr = await readLatest("restingHeartRate", U.bpm);
const steps = await readTodaySum("stepCount", "count"); const steps = await readTodaySum("stepCount", U.count);
const spo2 = await readLatest("oxygenSaturation", "%"); 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}`); console.log(`Results: weight=${weight?.value} bpSys=${bpSys?.value} bpDia=${bpDia?.value} hr=${hr?.value} rhr=${restingHr?.value} steps=${steps} spo2=${spo2?.value}`);