fix v7: wrap in async main() to avoid top-level await parse error
Scripting app's JavaScriptCore doesn't support top-level await in file scope. Wrapped everything in async main() + .then(Script.exit). Converted function declarations to arrow functions.
This commit is contained in:
parent
9c8dac7ec4
commit
270d6645f7
1 changed files with 157 additions and 156 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
// Health Sync v6 — reads Apple Health via Scripting app and POSTs to health-mcp server
|
// Health Sync v7 — reads Apple Health via Scripting app and POSTs to health-mcp server
|
||||||
// Run via Scripting app automation at 9:30am daily
|
// Run via Scripting app automation at 9:30am daily
|
||||||
// Server: http://chronos:9432/ingest
|
// Server: http://chronos:9432/ingest
|
||||||
//
|
//
|
||||||
|
|
@ -17,20 +17,21 @@ import { Script, Notification } from "scripting"
|
||||||
|
|
||||||
// icon-color: deep-blue; icon-glyph: heart;
|
// icon-color: deep-blue; icon-glyph: heart;
|
||||||
|
|
||||||
const SERVER_URL = "http://chronos:9432/ingest"
|
async function main() {
|
||||||
const API_KEY = "333f09ce904e9cbbe3b578fda393be92869122c7222dbccd"
|
const SERVER_URL = "http://chronos:9432/ingest"
|
||||||
|
const API_KEY = "333f09ce904e9cbbe3b578fda393be92869122c7222dbccd"
|
||||||
|
|
||||||
// --- Units for each quantity type ---
|
// --- Units for each quantity type ---
|
||||||
const U = {
|
const U = {
|
||||||
kg: HealthUnit.gramUnit(HealthUnitPrefix.kilo),
|
kg: HealthUnit.gramUnit(HealthUnitPrefix.kilo),
|
||||||
mmHg: HealthUnit.millimeterOfMercury(),
|
mmHg: HealthUnit.millimeterOfMercury(),
|
||||||
bpm: HealthUnit.count().divided(HealthUnit.minute()),
|
bpm: HealthUnit.count().divided(HealthUnit.minute()),
|
||||||
count: HealthUnit.count(),
|
count: HealthUnit.count(),
|
||||||
percent: HealthUnit.percent()
|
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) {
|
const readLatest = async (type, unit) => {
|
||||||
try {
|
try {
|
||||||
const samples = await Health.queryQuantitySamples(type, {
|
const samples = await Health.queryQuantitySamples(type, {
|
||||||
limit: 1,
|
limit: 1,
|
||||||
|
|
@ -48,10 +49,10 @@ async function readLatest(type, unit) {
|
||||||
console.log(`readLatest(${type}): error ${e}`)
|
console.log(`readLatest(${type}): error ${e}`)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sum all samples of a type since midnight. Returns a number or null.
|
// Sum all samples of a type since midnight. Returns a number or null.
|
||||||
async function readTodaySum(type, unit) {
|
const readTodaySum = async (type, unit) => {
|
||||||
try {
|
try {
|
||||||
const start = new Date()
|
const start = new Date()
|
||||||
start.setHours(0, 0, 0, 0)
|
start.setHours(0, 0, 0, 0)
|
||||||
|
|
@ -73,46 +74,46 @@ async function readTodaySum(type, unit) {
|
||||||
console.log(`readTodaySum(${type}): error ${e}`)
|
console.log(`readTodaySum(${type}): error ${e}`)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function todayDate() {
|
const todayDate = () => {
|
||||||
return new Date().toISOString().slice(0, 10)
|
return new Date().toISOString().slice(0, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function notify(body) {
|
const notify = async (body) => {
|
||||||
console.log(`notify: ${body}`)
|
console.log(`notify: ${body}`)
|
||||||
await Notification.schedule({
|
await Notification.schedule({
|
||||||
title: "Health Sync",
|
title: "Health Sync",
|
||||||
body: body
|
body: body
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Read all health metrics ---
|
// --- Read all health metrics ---
|
||||||
console.log("=== Health Sync starting ===")
|
console.log("=== Health Sync starting ===")
|
||||||
|
|
||||||
const weight = await readLatest("bodyMass", U.kg)
|
const weight = await readLatest("bodyMass", U.kg)
|
||||||
const bpSys = await readLatest("bloodPressureSystolic", U.mmHg)
|
const bpSys = await readLatest("bloodPressureSystolic", U.mmHg)
|
||||||
const bpDia = await readLatest("bloodPressureDiastolic", U.mmHg)
|
const bpDia = await readLatest("bloodPressureDiastolic", U.mmHg)
|
||||||
const hr = await readLatest("heartRate", U.bpm)
|
const hr = await readLatest("heartRate", U.bpm)
|
||||||
const restingHr = await readLatest("restingHeartRate", U.bpm)
|
const restingHr = await readLatest("restingHeartRate", U.bpm)
|
||||||
const steps = await readTodaySum("stepCount", U.count)
|
const steps = await readTodaySum("stepCount", U.count)
|
||||||
const spo2 = await readLatest("oxygenSaturation", U.percent)
|
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}`)
|
||||||
|
|
||||||
// --- Build samples array — only include metrics that have data ---
|
// --- Build samples array — only include metrics that have data ---
|
||||||
const samples = []
|
const samples = []
|
||||||
|
|
||||||
if (weight) {
|
if (weight) {
|
||||||
samples.push({
|
samples.push({
|
||||||
type: "weight",
|
type: "weight",
|
||||||
timestamp_utc: weight.startDate.toISOString(),
|
timestamp_utc: weight.startDate.toISOString(),
|
||||||
value: weight.value,
|
value: weight.value,
|
||||||
source: "apple_health"
|
source: "apple_health"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bpSys && bpDia) {
|
if (bpSys && bpDia) {
|
||||||
const bpValue = { systolic: bpSys.value, diastolic: bpDia.value }
|
const bpValue = { systolic: bpSys.value, diastolic: bpDia.value }
|
||||||
if (hr) bpValue.pulse = hr.value
|
if (hr) bpValue.pulse = hr.value
|
||||||
samples.push({
|
samples.push({
|
||||||
|
|
@ -121,51 +122,50 @@ if (bpSys && bpDia) {
|
||||||
value: bpValue,
|
value: bpValue,
|
||||||
source: "omron"
|
source: "omron"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hr && !bpSys) {
|
if (hr && !bpSys) {
|
||||||
samples.push({
|
samples.push({
|
||||||
type: "heart_rate",
|
type: "heart_rate",
|
||||||
timestamp_utc: hr.startDate.toISOString(),
|
timestamp_utc: hr.startDate.toISOString(),
|
||||||
value: hr.value,
|
value: hr.value,
|
||||||
source: "apple_health"
|
source: "apple_health"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (restingHr) {
|
if (restingHr) {
|
||||||
samples.push({
|
samples.push({
|
||||||
type: "resting_heart_rate",
|
type: "resting_heart_rate",
|
||||||
timestamp_utc: restingHr.startDate.toISOString(),
|
timestamp_utc: restingHr.startDate.toISOString(),
|
||||||
value: restingHr.value,
|
value: restingHr.value,
|
||||||
source: "apple_health"
|
source: "apple_health"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (steps !== null) {
|
if (steps !== null) {
|
||||||
samples.push({
|
samples.push({
|
||||||
type: "steps",
|
type: "steps",
|
||||||
timestamp_utc: todayDate(),
|
timestamp_utc: todayDate(),
|
||||||
value: steps,
|
value: steps,
|
||||||
source: "apple_health"
|
source: "apple_health"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spo2) {
|
if (spo2) {
|
||||||
samples.push({
|
samples.push({
|
||||||
type: "spo2",
|
type: "spo2",
|
||||||
timestamp_utc: spo2.startDate.toISOString(),
|
timestamp_utc: spo2.startDate.toISOString(),
|
||||||
value: spo2.value * 100, // HealthKit stores 0-1, server expects %
|
value: spo2.value * 100, // HealthKit stores 0-1, server expects %
|
||||||
source: "apple_health"
|
source: "apple_health"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Total samples to send: ${samples.length}`)
|
console.log(`Total samples to send: ${samples.length}`)
|
||||||
|
|
||||||
// --- POST to server ---
|
// --- POST to server ---
|
||||||
if (samples.length === 0) {
|
if (samples.length === 0) {
|
||||||
await notify("No health data found today")
|
await notify("No health data found today")
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(SERVER_URL, {
|
const response = await fetch(SERVER_URL, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
|
@ -183,8 +183,9 @@ if (samples.length === 0) {
|
||||||
console.log(`POST error: ${e}`)
|
console.log(`POST error: ${e}`)
|
||||||
await notify(`Error: ${e.message || e}`)
|
await notify(`Error: ${e.message || e}`)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("=== Health Sync done ===")
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("=== Health Sync done ===")
|
main().then(() => Script.exit())
|
||||||
Script.exit()
|
|
||||||
Loading…
Add table
Reference in a new issue