-
Notifications
You must be signed in to change notification settings - Fork 0
Derived Metrics
The integration computes a set of training-load and recovery metrics locally inside Home Assistant from the history it fetches (sleep ~60 days, workouts ~90 days). They are pure functions (no network), covered by deterministic unit tests. Inputs and units come from Data & Units; the sensors are listed in Sensors.
All of these are computed by this integration, not read from Suunto. CTL/ATL/TSB and ACWR are standard sports-science models; Readiness is a heuristic of our own (weights are our choice), not an official Suunto score.
A classic impulse-response model over your daily TSS (Training Stress Score from each workout).
- CTL - Chronic Training Load = "Fitness": an exponentially-weighted moving average of daily TSS with a 42-day time constant. Slow-moving; rises as you train consistently.
- ATL - Acute Training Load = "Fatigue": same EWMA but a 7-day time constant. Fast-moving; spikes after hard days.
- TSB - Training Stress Balance = "Form" = CTL - ATL (from the previous day). Positive → fresh / tapered; negative → fatigued / loading.
The recurrence each day is:
CTL += (TSS_today - CTL) / 42
ATL += (TSS_today - ATL) / 7
TSB = CTL_yesterday - ATL_yesterday
Seeding. The model is seeded with the window's mean daily TSS (a steady-state prior), not 0. Seeding from 0 would make the first weeks a big underestimate (and a constant training load would wrongly look like rising fitness). With the mean-seed + a 90-day window, a steady load gives CTL ~ ATL and TSB ~ 0, as it should.
Because the model needs ~90 days, the integration paginates the workouts fetch (up to 8x100). A short fetch window would truncate history and distort CTL.
ACWR = (last 7 days of TSS) / ((last 28 days of TSS) / 4)
i.e. this week's load vs the average week of the last four. Commonly cited "sweet spot" ~ 0.8-1.3; sustained values well above ~1.5 are associated with elevated injury risk. Returns unknown when there is no chronic load to divide by.
From the sleep-night series:
- Baseline = the mean of the nightly values; the spread is the population standard deviation (SD).
-
HRV status classifies the latest night against the baseline:
-
lowiflatest < mean - SD -
highiflatest > mean + SD -
balancedotherwise (and whenever SD is unavailable).
-
resting_hr uses the minimum sleeping heart rate as the nightly signal; resting_hr_baseline is its mean over the series.
A single "how ready are you today" score blending four components. The weights are our design choice - it is not an official Suunto metric. Higher sleep, HRV above baseline, resting HR below baseline, and a higher recovery balance all push the score up.
| Component | Weight | Score formula (clamped 0-100) |
|---|---|---|
| Sleep | 0.25 | sleep_hours / 8h x 100 |
| HRV vs baseline | 0.30 | 50 + (HRV - baseline)/baseline x 100 |
| Resting HR vs baseline | 0.20 | 50 + (baseline - RHR)/baseline x 100 |
| Recovery balance | 0.25 | balance_pct |
The final score is the weighted average of whichever components are available (weights renormalise if some inputs are missing). If none are available, the sensor is unknown.
For nights older than the recovery look-back window, the recovery-balance component is missing and the remaining weights renormalise - so a backfilled Readiness trend (in Long-term Statistics) for old nights is built from sleep + HRV + RHR only.
- As sensors (latest value): see Sensors → Training load and Recovery baselines & readiness.
- As daily long-term statistics for a gap-free trend (
suunto_app:readiness,:fitness_ctl,:fatigue_atl,:form_tsb,:sleep_hrv,:sleep_rhr, ...): see Long-term Statistics.
ha-suunto - Unofficial Suunto integration for Home Assistant - Not affiliated with Suunto / Amer Sports / Sports-Tracker - Report an issue
Getting started
Reference
Build with it
Under the hood
Help