From fb23796d7235827135183cbbcbc571ca4afe35c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 14 May 2026 13:23:33 +0200 Subject: [PATCH] feat(withings): ingest meastype 71 (current-gen Thermo) into BODY_TEMPERATURE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current-gen Withings Thermo and ScanWatch series report core body temperature under meastype 71 (the legacy meastype 12 stays in place for first-gen Thermo). Both decode through the same value × 10^unit path and target the BODY_TEMPERATURE enum slot. Skin temperature (meastype 73) stays out until v1.4.26 ships a SKIN_TEMPERATURE enum — surface temps (~32 °C) and core temps (~37 °C) must not share a rollup or correlation analytics will collapse. --- src/lib/withings/__tests__/client.test.ts | 14 ++++++++++++++ src/lib/withings/client.ts | 6 +++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/lib/withings/__tests__/client.test.ts b/src/lib/withings/__tests__/client.test.ts index 1b1a4060a..906621084 100644 --- a/src/lib/withings/__tests__/client.test.ts +++ b/src/lib/withings/__tests__/client.test.ts @@ -56,6 +56,20 @@ describe("MEASURE_TYPE_MAP", () => { it("maps Withings meastype 12 (legacy Thermo) → BODY_TEMPERATURE", () => { expect(MEASURE_TYPE_MAP[12]).toEqual({ type: "BODY_TEMPERATURE" }); }); + + it("maps Withings meastype 71 (current-gen Thermo) → BODY_TEMPERATURE", () => { + expect(MEASURE_TYPE_MAP[71]).toEqual({ type: "BODY_TEMPERATURE" }); + }); +}); + +describe("fetchMeasurements — body temperature (meastype 71)", () => { + it("decodes a current-gen Thermo reading into BODY_TEMPERATURE °C", async () => { + // 37.05 °C as Withings exponent encoding: value=3705, unit=-2. + installFetchMock(fakeGetmeasPayload([{ type: 71, value: 3705, unit: -2 }])); + const out = await fetchMeasurements("token"); + expect(out).toHaveLength(1); + expect(out[0]).toMatchObject({ type: "BODY_TEMPERATURE", value: 37.05 }); + }); }); describe("fetchMeasurements — temperature (meastype 12)", () => { diff --git a/src/lib/withings/client.ts b/src/lib/withings/client.ts index be39e63b2..5cbbfa3e8 100644 --- a/src/lib/withings/client.ts +++ b/src/lib/withings/client.ts @@ -129,8 +129,12 @@ export const MEASURE_TYPE_MAP: Record 11: { type: "PULSE" }, // Heart rate 6: { type: "BODY_FAT" }, // Body fat % // v1.4.25 — first-gen Thermo (WBT01) reports temperature as meastype 12; - // current-gen ships meastype 71 instead (see below). Both canonical °C. + // current-gen Thermo ships meastype 71. Both canonical °C, both into + // the BODY_TEMPERATURE bucket. Skin temperature (73, ScanWatch) stays + // out until v1.4.26 ships a SKIN_TEMPERATURE enum — surface temps + // (~32 °C) and core temps (~37 °C) must not share a rollup. 12: { type: "BODY_TEMPERATURE" }, + 71: { type: "BODY_TEMPERATURE" }, 77: { type: "TOTAL_BODY_WATER" }, // Hydration / water mass (kg) 88: { type: "BONE_MASS" }, // Bone mass (kg) 54: { type: "OXYGEN_SATURATION" }, // SpO2 (% — only ScanWatch / pulse-ox products)