components/PredictionCoreTempCard.ts
Purpose
This component renders a real-time “Predicted Core Body Temperature” card that combines:
- environmental heat stress (
WBGT) - user physiological profile data
- recent physical activity intensity
- ML/ONNX-based inference
to estimate a user’s current core body temperature and heat-risk state.
The component acts as a lightweight orchestration layer between:
- persistent user profile storage
- activity aggregation services
- inference/model execution
- UI state classification
- periodic polling behavior
It continuously refreshes prediction inputs, executes inference on a fixed cadence, and presents the result as a compact dashboard card.
Primary responsibilities include:
- loading and normalizing user profile inputs
- collecting rolling activity CPM averages
- executing core temperature inference
- preventing duplicate inference runs
- classifying heat-risk states
- rendering inference metadata and diagnostics
- handling inference failures gracefully
Invariants
Core Temperature Prediction Contract
The component only renders a valid prediction when all required inputs exist:
- finite
wbgt - loaded user profile
- valid recent CPM activity history
If any required input is unavailable:
- inference is skipped
- output resets to placeholder values
Prediction Polling Cadence
Inference runs on a fixed interval:
pollMs (default: 5000ms)
The component guarantees:
- only one active interval exists
- intervals are cleaned up on unmount
Single Inference Execution
Concurrent inference runs are prevented through:
isInferenceRunning.current
This guarantees:
- only one inference executes at a time
- overlapping async executions cannot occur
Input De-Duplication
Inference only reruns when inputs materially change.
A deterministic serialized key is generated from:
- WBGT
- gender
- age
- BMI
- activity history
- CPM average
Repeated identical inputs are skipped.
Profile Normalization
Loaded profile data is normalized into bounded model-safe values.
BMI Bounds
BMI is clamped to:
10 ≤ BMI ≤ 60
using:
clamp()
Gender Encoding
User gender is normalized into model-compatible integer encodings:
| Profile Value | Encoded |
|---|---|
| male | 1 |
| female | 2 |
| other/unknown | 0 |
Safe Defaults
If profile loading fails or data is incomplete, the component falls back to deterministic defaults:
| Field | Default |
|---|---|
| gender | 1 |
| age | 25 |
| BMI | 24.0 |
| daysActive14 | 0 |
This guarantees inference always receives structurally valid inputs.
CPM Dependency
Inference requires a valid rolling 40-minute CPM average.
If CPM history is unavailable:
- prediction is withheld
- UI enters “Collecting…” state
- no inference occurs
Alert De-Duplication
Repeated identical inference failures only display one alert.
Alerts are deduplicated using:
lastAlertKey.current
This prevents alert spam during repeated polling failures.
Focus Refresh Behavior
Whenever the screen regains focus:
- profile data reloads
- inference cache resets
- next prediction is forced to recompute
This ensures predictions always reflect the newest profile state.
Risk Classification Thresholds
Predicted temperatures are classified into fixed severity bands:
| Temperature | State |
|---|---|
< 38.0°C | Normal |
38.0–38.9°C | Warning |
≥ 39.0°C | High |
These thresholds are deterministic and UI-only.
Variants
Model Backend Variant
Inference may execute through different model backends:
| Backend | Meaning |
|---|---|
onnx | ML inference model |
baseline | fallback heuristic model |
— | unavailable |
The selected backend is surfaced in the UI footer.
BMI Source Variant
BMI may originate from multiple sources:
Calculated BMI
Computed from:
- height
- weight
using:
calcBMI()
Default BMI
Used when anthropometric data is unavailable.
Stored BMI
Reserved for future persisted BMI support.
Activity Availability Variant
CPM Available
- prediction runs
- core temp displayed
- status shows “OK”
CPM Unavailable
- prediction withheld
- placeholder values shown
- collection status displayed
Profile Loading Variant
Successful Load
Uses persisted user demographics and activity metadata.
Failed Load
Falls back to safe defaults.
The UI remains operational in both cases.
WBGT Availability Variant
Valid WBGT
Inference allowed.
Invalid WBGT
Prediction disabled and reported as missing input.
Prediction State Variant
The component supports several visual output states:
| State | Meaning |
|---|---|
| placeholder | prediction unavailable |
| normal | low-risk core temperature |
| warning | elevated heat strain |
| high | dangerous heat strain |
Each state maps to unique badge colors and labels.
Polling Lifecycle Variant
Inference lifecycle changes based on component state:
| State | Behavior |
|---|---|
| mounted | polling active |
| unfocused | focus refresh pending |
| unmounted | polling stopped |
Exports
PredictionCoreTempCard
const PredictionCoreTempCard: React.FC<Props>
Primary exported component.
Responsibilities include:
- profile hydration
- activity retrieval
- inference orchestration
- polling management
- result classification
- prediction rendering
Props
Props
type Props = {
wbgt: number;
wbgtLabel?: string;
title?: string;
pollMs?: number;
};
wbgt
Precomputed WBGT input used for prediction inference.
Expected in Celsius.
wbgtLabel
Optional UI label for the WBGT field.
Examples:
"WBGT Sun""WBGT Shade"
title
Optional card title override.
Default:
Core Temp Prediction
pollMs
Inference refresh cadence in milliseconds.
Default:
5000
Internal State
Input State
Maintains normalized inference inputs:
genderagebmidaysActive14cpm
Output State
Tracks inference outputs:
- formatted temperature string
- numeric temperature
- active model backend
Status State
Tracks operational metadata:
- CPM collection status
- BMI source
- alert suppression state
- profile load state
Internal Helper Logic
clamp(v, lo, hi)
Bounds numeric values into safe ranges.
Used primarily for BMI normalization.
loadProfileFromStorage()
Loads and normalizes persisted user profile data.
Responsibilities include:
- demographic normalization
- BMI computation
- fallback handling
- activity metadata extraction
buildInputKey(cpm40)
Builds a deterministic serialized inference signature.
Used to prevent redundant inference execution.
Rendering Architecture
The card is split into two primary sections:
| Section | Purpose |
|---|---|
| Inputs | displays inference inputs |
| Result | displays prediction output |
Input Panel
Displays:
- WBGT
- activity CPM
- gender
- BMI
- age
- recent activity history
Result Panel
Displays:
- predicted core temperature
- severity badge
- model backend
- CPM collection status
Error Handling
Inference failures are:
- logged through
global.log - surfaced through
Alert.alert - deduplicated to avoid repeated alerts
The component attempts to remain operational after failures rather than entering a fatal state.