Provides access to hardware device sensors including accelerometer, gyroscope, magnetometer, barometer, light sensor, and pedometer for React Native and Expo applications.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
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: