feat(measurements): accept indoor CO2, temperature and humidity

Room climate from a home automation system gets three types of its own:
INDOOR_CO2 (ppm), INDOOR_TEMPERATURE (celsius, shown in Fahrenheit for
imperial readers) and INDOOR_HUMIDITY (percent). They arrive through the
existing ingest token (measurements:write, source EXTERNAL), sit in the
environment cluster beside daylight, and the daily rollup carries their
mean, low and high like any spot reading. They never mix with the body
temperatures or with the outdoor environment channels.

The Home Assistant page documents the three types, a rest_command that
sends a room as one request, a single-room automation, and an
importable blueprint (docs/integrations/blueprints) that skips sensors
reporting unknown or non-numeric states, converts Fahrenheit, and
stamps readings to the minute so a retried push is refused rather than
written twice.
This commit is contained in:
Marc-André Bombeck committed 2026-10-21 20:26:15 +02:00
1 parent b76826a5f8
commit cc8ea3dfbb
32 files changed
+463 -9

No files matched your search

+11
View File
@@ -153,6 +153,10 @@ export const measurementTypeEnum = z.enum([
"MINDFUL_MINUTES",
"STATE_OF_MIND_VALENCE",
"AFIB_BURDEN",
// ── v1.44 — room climate pushed through the ingest token ──
"INDOOR_CO2",
"INDOOR_TEMPERATURE",
"INDOOR_HUMIDITY",
]);
/**
@@ -460,6 +464,13 @@ export const VALUE_RANGES: Record<string, { min: number; max: number }> = {
// AFib burden as a percent of the week, after the ×100 scaling. A client
// that already scaled sends 2 for 2 %, which lands at 200 and is refused.
AFIB_BURDEN: { min: 0, max: 100 },
// ── v1.44 — room climate. CO2: outdoor air sits near 420 ppm and a closed
// bedroom can pass 3000; consumer sensors top out at 5000–10000 ppm.
INDOOR_CO2: { min: 0, max: 10000 },
// Indoor air °C: a cold cellar to an overheated attic.
INDOOR_TEMPERATURE: { min: -20, max: 60 },
// Relative humidity, percent.
INDOOR_HUMIDITY: { min: 0, max: 100 },
// Grip strength kg — a child can read in the single digits, an elite athlete
// tops ~90 kg; 120 is a generous ceiling that still rejects sensor noise.
GRIP_STRENGTH: { min: 0, max: 120 },