sessionMonitor.ts
Purpose
This module manages the user-initiated “active monitoring session” — the equivalent of a workout mode. On iOS it uses a continuous GPS location watch to keep the app alive in the background, throttled to run the prediction pipeline at most once per minute. On Android it delegates to the react-native-background-actions foreground service.
Its responsibilities include:
- Persisting session active state to AsyncStorage so it survives app restarts
- Starting and stopping iOS GPS location watching with appropriate options
- Starting and stopping the Android background foreground service
- Throttling iOS pipeline runs to at most one per
MIN_INTERVAL_MS - Notifying registered prediction listeners after each pipeline run
- Exposing a subscription API for the
PredictionScreento react to new results
Invariants
Single Watch Guard
startSession no-ops if watchId is already set, preventing duplicate location watchers from being registered.
Throttle Gate
On iOS, each location update checks Date.now() - lastRunMs < MIN_INTERVAL_MS before running the pipeline.
Throttled updates log a debug message with the remaining cooldown in seconds but do not run inference.
AsyncStorage Session Flag
Session state is persisted to AsyncStorage under "heatsafe_session_active" so isSessionActive() can return the correct value even after a cold start.
stopSession explicitly writes "false" rather than deleting the key, ensuring the flag is always present after the first session.
iOS Location Options
| Option | Value | Rationale |
|---|---|---|
enableHighAccuracy | false | Low-power; only approximate location needed for weather |
distanceFilter | 0 | Fire on every update; throttle handles rate limiting |
showsBackgroundLocationIndicator | true | Required for App Store transparency (blue status-bar pill) |
pauseUpdatesAutomatically | false | Prevent iOS from pausing updates during inactivity |
Android Permission Before Service Start
requestPersistenceNotificationPermission is called before BackgroundService.start to satisfy the Android 13+ foreground service notification requirement.
If the service is already running (BackgroundService.isRunning()), startSession does not start a second instance.
Exports
predictionListeners
let predictionListeners: PredictionListener[]
Mutable array of listener callbacks invoked after each successful pipeline run. Also used by background.ts to notify the foreground after Android background predictions.
subscribeToPredictions(...)
function subscribeToPredictions(listener: () => void): () => void
Registers a prediction listener and returns an unsubscribe function.
isSessionActive()
async function isSessionActive(): Promise<boolean>
Returns true if the session flag in AsyncStorage is "true". Returns false on storage errors.
startSession()
async function startSession(): Promise<void>
Starts the monitoring session for the current platform. On iOS, begins GPS location watching. On Android, starts the foreground service.
stopSession()
async function stopSession(): Promise<void>
Stops the monitoring session. Clears the GPS watcher (iOS), stops the background service (Android), and writes "false" to the session flag.