bridge: update README for the Daily Values / Measurements architecture
Replace the outdated /entries-only description with the three-endpoint model, document daily_totals-based steps sourcing, and move sleep_duration to "not yet covered" with an explanation of why (not implemented in Health v3 at all, not just disabled for this user).
This commit is contained in:
+46
-9
@@ -1,8 +1,16 @@
|
|||||||
# Bridge: Life Dashboard Companion → Nextcloud Health v3
|
# Bridge: Life Dashboard Companion → Nextcloud Health v3
|
||||||
|
|
||||||
Minimal MVP. Forwards only the `weight` records from the Companion webhook
|
Forwards the Health Connect types that are both sent by the Companion app and
|
||||||
payload to Health v3's `POST /entries` endpoint, one entry per record, since
|
supported by Health v3, split across Health's three write APIs:
|
||||||
weight is currently the only OpenScale-relevant metric Health v3 has built in.
|
|
||||||
|
- **Daily Values** (`PUT /daily-values/{metricKey}/{date}`, one upsert per
|
||||||
|
calendar day): `weight`, `steps`.
|
||||||
|
- **Measurements** (`POST /measurements`, one call per timestamped reading):
|
||||||
|
`pulse` (heart rate).
|
||||||
|
|
||||||
|
Which metrics a given Health instance actually knows is detected at startup
|
||||||
|
via `GET /configuration`, since shipped releases can lag behind the
|
||||||
|
documented API (see "Not yet covered" below).
|
||||||
|
|
||||||
Requires Python 3.10+ (uses `str | None` type hints).
|
Requires Python 3.10+ (uses `str | None` type hints).
|
||||||
|
|
||||||
@@ -20,21 +28,50 @@ uv run server.py
|
|||||||
|
|
||||||
Point the Companion app's webhook URL at `http://<this-host>:8080/webhook/health-connect`.
|
Point the Companion app's webhook URL at `http://<this-host>:8080/webhook/health-connect`.
|
||||||
|
|
||||||
|
Set `NC_TIMEOUT_SECONDS` (default `30`) if your Nextcloud instance responds slowly.
|
||||||
|
|
||||||
## Scope
|
## Scope
|
||||||
|
|
||||||
|
- On startup, fetches `GET /configuration` and only forwards metrics the
|
||||||
|
Health instance actually knows; unknown metrics are logged and skipped
|
||||||
|
instead of failing every request with an error. Metrics it knows but has
|
||||||
|
disabled for the user are enabled automatically via `PUT /configuration`.
|
||||||
- Verifies `X-Signature: sha256=<hmac>` on every request; rejects with 401 on
|
- Verifies `X-Signature: sha256=<hmac>` on every request; rejects with 401 on
|
||||||
mismatch (Companion does not retry on 401).
|
mismatch (Companion does not retry on 401).
|
||||||
- Only reads the `weight` array; everything else in the payload is ignored.
|
- Reads `weight`, `daily_totals` (for steps), and `heart_rate` from the
|
||||||
- Uses the Health Connect record `uuid` as Health's `operationId` for
|
payload; everything else is ignored.
|
||||||
idempotent retries where it parses as a UUID.
|
- Steps use Companion's `daily_totals`, which Health Connect already
|
||||||
|
deduplicates across sources (phone, watch, ...) into one total per day;
|
||||||
|
summing the raw per-window `steps` records ourselves would double-count,
|
||||||
|
so those are ignored in favor of the daily total.
|
||||||
|
- Weight uses the UTC calendar date of each reading as the Daily Value's
|
||||||
|
date key (Health doesn't expose the owning user's timezone to this
|
||||||
|
bridge), so a reading taken right around local midnight could land on the
|
||||||
|
"wrong" day.
|
||||||
|
- Heart rate: handles both raw records (`bpm`/`time`) and bucketed
|
||||||
|
resolution windows (`bucket_start`/`avg`); bucketed windows get a
|
||||||
|
deterministic id derived from the window since they carry no HC uuid.
|
||||||
|
- Daily Value writes are idempotent by construction (one value per
|
||||||
|
metric/date, last write wins); Measurement writes use the Health Connect
|
||||||
|
record `uuid` (or a derived id for bucketed windows) as Health's
|
||||||
|
`operationId` for idempotent retries.
|
||||||
- Returns 502 on partial forwarding failure so the Companion app retries the
|
- Returns 502 on partial forwarding failure so the Companion app retries the
|
||||||
whole payload later (transient failures are retried by the app).
|
whole payload later (transient failures are retried by the app).
|
||||||
|
|
||||||
## Not yet covered
|
## Not yet covered
|
||||||
|
|
||||||
- Body fat / muscle mass / body water (not yet built into Health v3; muscle
|
- Sleep duration: despite being documented in Health v3's data model, it
|
||||||
mass and body water aren't even on Health v3's roadmap — see the main
|
isn't an actual Daily Value, Measurement, or journal metric in the shipped
|
||||||
|
app yet (absent from `GET /configuration`'s metric list entirely), so
|
||||||
|
there's currently no endpoint to send it to.
|
||||||
|
- Blood pressure, body fat, blood glucose, oxygen saturation, and
|
||||||
|
temperature: the Companion app doesn't send these Health Connect types at
|
||||||
|
all yet.
|
||||||
|
- Muscle mass and body water: not on Health v3's roadmap at all (see the main
|
||||||
README's architecture diagram).
|
README's architecture diagram).
|
||||||
- Blood pressure, steps, activity (add once this MVP is proven out).
|
- Hydration and exercise/movement: both apps have these concepts, but with
|
||||||
|
incompatible shapes (a volume/duration in Companion vs. a closed set of
|
||||||
|
event options in Health), so a faithful mapping isn't possible without
|
||||||
|
lossy guessing.
|
||||||
- Containerized deployment (currently a local script only, per the current
|
- Containerized deployment (currently a local script only, per the current
|
||||||
iteration's scope).
|
iteration's scope).
|
||||||
|
|||||||
Reference in New Issue
Block a user