sensorRecorder.ts
Purpose
This module provides background-safe access to motion data on iOS by reading from the CoreMotion motion coprocessor and the device pedometer. Because coprocessor recording operates independently of app state, this module is the primary data source for CPM computation during background task wakes.
Its responsibilities include:
- Querying the system pedometer for step count over an arbitrary historical window
- Computing CPM from pedometer step counts as a lightweight fallback
- Starting a timed CoreMotion accelerometer recording session via the native module
- Querying the most recent 1-minute CPM value from the native coprocessor buffer
- Querying per-chunk CPM values across a longer coprocessor recording window
- Averaging per-chunk CPM values into a single representative value
- Logging all query results and errors with structured log entries
Invariants
iOS-Only Native Module
HeatSafeSensorRecorder is loaded conditionally: it is null on Android.
All functions that depend on it (startAccelerometerRecording, getLatestMinuteCPM, getCPMFromRecordedAccelerometer) return a safe null/false value immediately when the module is unavailable, without throwing.
Pedometer Availability Check
All pedometer-dependent operations call Pedometer.isAvailableAsync() before querying.
If the pedometer is unavailable, getCPMFromPedometer returns 0 and logs a WARN. It never throws.
CPM from Pedometer Zero-Guard
When the requested fromSeconds is 0 or negative, the CPM computation returns 0 rather than dividing by zero.
Minimum Data Guard — Coprocessor
getCPMFromRecordedAccelerometer returns null when the native module returns an empty chunks array.
This signals that fewer than 3 minutes of coprocessor data are available, which is enforced by the native side.
getLatestMinuteCPM returns null when the native module signals insufficient data (less than 1 minute available).
Error Containment
All native module calls are wrapped in try/catch.
Errors are logged at ERROR level and a safe default is returned (false, 0, or null depending on the function). No error propagates to the caller.
Variants
CPM Sources
The module exposes two distinct CPM data sources with different characteristics:
| Source | Function | Accuracy | Background-safe |
|---|---|---|---|
| Pedometer (step count) | getCPMFromPedometer | Step-based proxy | Yes |
| Coprocessor (raw accelerometer) | getCPMFromRecordedAccelerometer | Full AUC pipeline | Yes |
| Coprocessor (latest minute) | getLatestMinuteCPM | Native pipeline | Yes |
Coprocessor Chunk Averaging
getCPMFromRecordedAccelerometer returns the mean of all per-chunk CPM values alongside the raw chunks array.
Individual chunks represent non-overlapping 60-second windows computed by the native module. The average field is the arithmetic mean across all returned chunks.
Exports
isSensorRecorderAvailable()
async function isSensorRecorderAvailable(): Promise<boolean>
Returns true if the device pedometer is available. Does not check native module availability separately.
getCPMFromPedometer(...)
async function getCPMFromPedometer(fromSeconds: number): Promise<number>
Queries the system pedometer for the step count over the last fromSeconds and returns the average CPM.
Parameters
| Parameter | Description |
|---|---|
fromSeconds | Historical window length in seconds |
Returns
CPM as a number. Returns 0 if the pedometer is unavailable, the window is zero-length, or an error occurs.
startAccelerometerRecording(...)
async function startAccelerometerRecording(durationSeconds: number): Promise<boolean>
Asks the CoreMotion coprocessor to record raw accelerometer data for durationSeconds. Safe to call during a background wake. Returns false on Android or on any native error.
getLatestMinuteCPM()
async function getLatestMinuteCPM(): Promise<number | null>
Returns the CPM for the most recent 60-second coprocessor recording window, or null if fewer than 1 minute of data is available or the native module is absent.
getCPMFromRecordedAccelerometer(...)
async function getCPMFromRecordedAccelerometer(fromSeconds: number): Promise<AccelerometerCpmResult | null>
Returns per-chunk CPM values and their average for the last fromSeconds of coprocessor data, or null if fewer than 3 minutes of data are available.
Parameters
| Parameter | Description |
|---|---|
fromSeconds | Historical window to query from the coprocessor |
AccelerometerCpmResult
type AccelerometerCpmResult = {
average: number;
chunks: number[];
};
| Field | Description |
|---|---|
average | Arithmetic mean CPM across all returned chunks |
chunks | Per-minute CPM values from the coprocessor pipeline |