Pedometer functionality for fitness and health applications with step counting and historical data access.
Provides access to device step counting capabilities for fitness tracking and health applications.
/**
* Subscribe to pedometer updates for real-time step counting
* @param callback - Callback invoked when new step count data is available
* @returns Subscription that enables calling remove() to unsubscribe
*/
function watchStepCount(callback: PedometerUpdateCallback): Subscription;
/**
* Get the step count between two dates (iOS only)
* @param start - Date indicating the start of the range over which to measure steps
* @param end - Date indicating the end of the range over which to measure steps
* @returns Promise that fulfills with PedometerResult
* @platform ios
*/
function getStepCountAsync(start: Date, end: Date): Promise<PedometerResult>;
/**
* Returns whether the pedometer is enabled on the device
* @returns Promise that fulfills with boolean indicating pedometer availability
*/
function isAvailableAsync(): Promise<boolean>;
/**
* Checks user's permissions for accessing pedometer
* @returns Promise resolving to PermissionResponse
*/
function getPermissionsAsync(): Promise<PermissionResponse>;
/**
* Asks the user to grant permissions for accessing pedometer
* @returns Promise resolving to PermissionResponse
*/
function requestPermissionsAsync(): Promise<PermissionResponse>;
interface PedometerResult {
/** Number of steps taken between the given dates */
steps: number;
}
type PedometerUpdateCallback = (result: PedometerResult) => void;Basic Usage Examples:
import { Pedometer } from "expo-sensors";
// Check if pedometer is available
const isAvailable = await Pedometer.isAvailableAsync();
if (!isAvailable) {
console.log("Pedometer not available on this device");
return;
}
// Request permissions (primarily for iOS)
const { status } = await Pedometer.requestPermissionsAsync();
if (status !== 'granted') {
console.log("Pedometer permission not granted");
return;
}
// Subscribe to real-time step updates
const subscription = Pedometer.watchStepCount(({ steps }) => {
console.log(`Steps taken: ${steps}`);
});
// Clean up subscription when done
subscription.remove();Historical Step Data (iOS only):
import { Pedometer } from "expo-sensors";
// Get steps for the last 24 hours
const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);
const now = new Date();
try {
const result = await Pedometer.getStepCountAsync(oneDayAgo, now);
console.log(`Steps in last 24 hours: ${result.steps}`);
} catch (error) {
console.log("Error fetching step count:", error);
}
// Get steps for specific time periods
async function getStepsForPeriod(days: number): Promise<number> {
const startDate = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
const endDate = new Date();
try {
const result = await Pedometer.getStepCountAsync(startDate, endDate);
return result.steps;
} catch (error) {
console.log(`Error getting steps for ${days} days:`, error);
return 0;
}
}
// Usage examples
const todaySteps = await getStepsForPeriod(1);
const weekSteps = await getStepsForPeriod(7);
console.log(`Today: ${todaySteps} steps, This week: ${weekSteps} steps`);Daily Step Goal Tracker:
import { Pedometer } from "expo-sensors";
interface StepGoal {
daily: number;
weekly: number;
progress: number; // 0-1 (percentage)
}
class StepTracker {
private dailyGoal = 10000;
private weeklyGoal = 70000;
private currentSteps = 0;
async startTracking(onProgress: (goal: StepGoal) => void) {
// Check availability and permissions
const isAvailable = await Pedometer.isAvailableAsync();
if (!isAvailable) {
throw new Error("Pedometer not available");
}
const { status } = await Pedometer.requestPermissionsAsync();
if (status !== 'granted') {
throw new Error("Pedometer permission denied");
}
// Subscribe to real-time updates
const subscription = Pedometer.watchStepCount(({ steps }) => {
this.currentSteps = steps;
const progress = Math.min(steps / this.dailyGoal, 1);
onProgress({
daily: this.dailyGoal,
weekly: this.weeklyGoal,
progress: progress
});
// Check if goal is reached
if (steps >= this.dailyGoal && progress >= 1) {
this.onGoalReached();
}
});
return subscription;
}
setDailyGoal(steps: number) {
this.dailyGoal = steps;
}
private onGoalReached() {
console.log(`π Daily goal of ${this.dailyGoal} steps reached!`);
// Trigger notification or celebration animation
}
async getWeeklyStats(): Promise<{ totalSteps: number; dailyAverage: number; goalProgress: number }> {
try {
const weekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
const now = new Date();
const result = await Pedometer.getStepCountAsync(weekAgo, now);
const totalSteps = result.steps;
const dailyAverage = Math.round(totalSteps / 7);
const goalProgress = Math.min(totalSteps / this.weeklyGoal, 1);
return { totalSteps, dailyAverage, goalProgress };
} catch (error) {
console.log("Error getting weekly stats:", error);
return { totalSteps: 0, dailyAverage: 0, goalProgress: 0 };
}
}
}
// Usage
const tracker = new StepTracker();
tracker.setDailyGoal(12000);
const subscription = await tracker.startTracking(({ daily, progress }) => {
const percentage = Math.round(progress * 100);
console.log(`Progress: ${percentage}% of ${daily} daily step goal`);
});Activity Level Monitor:
import { Pedometer } from "expo-sensors";
type ActivityLevel = 'sedentary' | 'lightly_active' | 'moderately_active' | 'very_active';
class ActivityMonitor {
private stepHistory: Array<{ timestamp: number; steps: number }> = [];
private lastStepCount = 0;
startMonitoring(onActivityChange: (level: ActivityLevel, stepsPerMinute: number) => void) {
const subscription = Pedometer.watchStepCount(({ steps }) => {
const now = Date.now();
const stepsSinceLastUpdate = steps - this.lastStepCount;
// Record step data with timestamp
this.stepHistory.push({ timestamp: now, steps: stepsSinceLastUpdate });
this.lastStepCount = steps;
// Keep only last 10 minutes of data
const tenMinutesAgo = now - 10 * 60 * 1000;
this.stepHistory = this.stepHistory.filter(entry => entry.timestamp > tenMinutesAgo);
// Calculate activity level
const activityLevel = this.calculateActivityLevel();
const stepsPerMinute = this.calculateStepsPerMinute();
onActivityChange(activityLevel, stepsPerMinute);
});
return subscription;
}
private calculateActivityLevel(): ActivityLevel {
if (this.stepHistory.length < 2) return 'sedentary';
const stepsPerMinute = this.calculateStepsPerMinute();
if (stepsPerMinute < 1) return 'sedentary';
if (stepsPerMinute < 30) return 'lightly_active';
if (stepsPerMinute < 60) return 'moderately_active';
return 'very_active';
}
private calculateStepsPerMinute(): number {
if (this.stepHistory.length < 2) return 0;
const totalSteps = this.stepHistory.reduce((sum, entry) => sum + entry.steps, 0);
const timeSpan = this.stepHistory[this.stepHistory.length - 1].timestamp - this.stepHistory[0].timestamp;
const minutes = timeSpan / (1000 * 60);
return minutes > 0 ? totalSteps / minutes : 0;
}
}
// Usage
const activityMonitor = new ActivityMonitor();
const subscription = activityMonitor.startMonitoring((level, stepsPerMinute) => {
console.log(`Activity Level: ${level}, Steps/min: ${stepsPerMinute.toFixed(1)}`);
// Provide feedback based on activity level
switch (level) {
case 'sedentary':
console.log("πΊ Consider taking a short walk!");
break;
case 'lightly_active':
console.log("πΆ Nice gentle movement!");
break;
case 'moderately_active':
console.log("π Great activity level!");
break;
case 'very_active':
console.log("β‘ Excellent workout pace!");
break;
}
});Health Integration Example:
import { Pedometer } from "expo-sensors";
interface HealthMetrics {
steps: number;
estimatedCalories: number;
estimatedDistance: number; // in kilometers
activeMinutes: number;
}
class HealthTracker {
private userWeight = 70; // kg (default)
private strideLength = 0.76; // meters (default)
private startTime = Date.now();
private totalSteps = 0;
setUserProfile(weight: number, strideLength: number) {
this.userWeight = weight;
this.strideLength = strideLength;
}
startHealthTracking(onUpdate: (metrics: HealthMetrics) => void) {
const subscription = Pedometer.watchStepCount(({ steps }) => {
this.totalSteps = steps;
const metrics = this.calculateHealthMetrics();
onUpdate(metrics);
});
return subscription;
}
private calculateHealthMetrics(): HealthMetrics {
const steps = this.totalSteps;
// Estimate calories burned (rough calculation)
// Formula: steps * weight(kg) * 0.0005
const estimatedCalories = Math.round(steps * this.userWeight * 0.0005);
// Estimate distance
const estimatedDistance = (steps * this.strideLength) / 1000; // Convert to km
// Calculate active minutes (assuming 100+ steps per minute indicates activity)
const elapsedMinutes = (Date.now() - this.startTime) / (1000 * 60);
const averageStepsPerMinute = steps / elapsedMinutes;
const activeMinutes = averageStepsPerMinute > 100 ? Math.round(elapsedMinutes * 0.7) : 0;
return {
steps,
estimatedCalories,
estimatedDistance: Math.round(estimatedDistance * 100) / 100, // 2 decimal places
activeMinutes
};
}
async getDailyReport(): Promise<HealthMetrics> {
try {
const startOfDay = new Date();
startOfDay.setHours(0, 0, 0, 0);
const now = new Date();
const result = await Pedometer.getStepCountAsync(startOfDay, now);
const steps = result.steps;
const estimatedCalories = Math.round(steps * this.userWeight * 0.0005);
const estimatedDistance = Math.round((steps * this.strideLength / 1000) * 100) / 100;
// Estimate active minutes for the day
const hoursElapsed = (now.getTime() - startOfDay.getTime()) / (1000 * 60 * 60);
const activeMinutes = Math.round(hoursElapsed * 0.1 * (steps / 1000)); // Rough estimate
return { steps, estimatedCalories, estimatedDistance, activeMinutes };
} catch (error) {
console.log("Error getting daily report:", error);
return { steps: 0, estimatedCalories: 0, estimatedDistance: 0, activeMinutes: 0 };
}
}
}
// Usage
const healthTracker = new HealthTracker();
healthTracker.setUserProfile(75, 0.78); // 75kg, 78cm stride
const subscription = healthTracker.startHealthTracking((metrics) => {
console.log(`π Health Metrics:`);
console.log(` Steps: ${metrics.steps}`);
console.log(` Calories: ${metrics.estimatedCalories} kcal`);
console.log(` Distance: ${metrics.estimatedDistance} km`);
console.log(` Active: ${metrics.activeMinutes} min`);
});Background Updates:
Data Limitations:
Alternative Solutions: