WellAlly Logo
WellAlly康心伴
Development

Smart Alarm: Wake During Light Sleep (React Native + Accelerometer)

Wake up refreshed, not groggy. Accelerometer-based sleep phase detection, 30-minute wake window, and Expo Sensors implementation. React Native smart alarm—complete code.

W
2025-12-12
Verified 2025-12-20
9 min read

Key Takeaways

  • Accelerometer-based sleep detection estimates sleep stages by measuring movement intensity
  • Smart alarms monitor activity within a 30-minute window before target wake time
  • Expo Sensors library provides cross-platform accelerometer access
  • Movement threshold calibration is crucial for accurate detection
  • Privacy-first design keeps all sleep data on-device

Who This Guide Is For

This guide is for React Native developers building sleep tracking or smart alarm applications. You should have solid understanding of React Native hooks, Expo framework, and mobile sensor APIs. If you're creating wellness apps, alarm applications, or any product requiring motion-based sleep detection, this guide is for you.


Key Takeaways

  • Accelerometer-Based Sleep Detection: Phone accelerometers can estimate sleep stages by measuring movement intensity during sleep—more movement indicates lighter sleep phases.
  • Wake-Up Window Strategy: Smart alarms work by monitoring activity within a 30-minute window before the target time and triggering during periods of increased movement.
  • Expo Sensors Integration: The expo-sensors library provides cross-platform access to device sensors, making it easy to implement motion-based features in React Native apps.
  • Movement Threshold Tuning: The MOVEMENT_THRESHOLD value is crucial and requires calibration—too sensitive causes false alarms, too insensitive misses wake opportunities.
  • Privacy-First Approach: All sleep data remains on the device with no server transmission, making this approach inherently privacy-preserving for health applications.

Ever jolted awake by a blaring alarm feeling groggy and disoriented? This feeling, known as sleep inertia, is often the result of being woken up during a deep sleep cycle. What if your alarm could intelligently wait for the optimal moment to wake you? That's the idea behind the "Smart Alarm" – a mobile app that uses your phone's accelerometer to estimate your sleep cycles and wake you during your lightest sleep phase.

In this project showcase, we'll walk through the creation of a mobile app that does just that. We'll explore the science behind sleep tracking with motion sensors, the challenges of interpreting accelerometer data, and the step-by-step implementation using React Native. This project is a fantastic blend of mobile development, data science, and health tech, offering a practical look at how we can use the power in our pockets to improve our well-being.

Prerequisites:

  • Familiarity with React Native and JavaScript (ES6+).
  • A physical device for testing (simulators don't have accelerometers).
  • Node.js and a React Native development environment set up.

Understanding the Problem

Traditional alarms are simple: they go off at a fixed time, regardless of your sleep state. However, our sleep is cyclical, moving between light, deep, and REM stages. Waking up from a light sleep stage feels much more natural and leaves you feeling more refreshed.

The challenge is to determine these sleep stages without the advanced equipment of a sleep lab. This is where the accelerometer comes in. By placing your phone on your bed, it can detect your movements throughout the night. The core idea is that we move more during lighter sleep phases and are relatively still during deep sleep.

While not as precise as clinical methods like polysomnography, accelerometer-based tracking is a reliable way to estimate sleep patterns for consumer applications. Our approach will be to capture this motion data, process it to identify periods of low and high activity, and use this information to trigger the alarm at the right time.

Prerequisites

Before we start coding, let's get our environment ready.

  • React Native Project: If you don't have a project, create one using Expo:

    code
    npx create-expo-app SmartAlarm
    cd SmartAlarm
    
    Code collapsed
  • Required Libraries: We'll need a library to access the accelerometer. expo-sensors is an excellent choice for this.

    code
    npx expo install expo-sensors
    
    Code collapsed
  • Version Compatibility: This tutorial uses Expo SDK 50 and expo-sensors v13.0.0.

Step 1: Accessing Accelerometer Data

What we're doing

First, we need to get a continuous stream of data from the phone's accelerometer. The accelerometer measures acceleration forces along the x, y, and z axes. We'll set up a listener that captures this data and stores it in our component's state.

Implementation

Create a new file src/SleepTracker.js. This component will handle all the logic for tracking sleep.

code
// src/components/SleepTracker.js
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { Accelerometer } from 'expo-sensors';

const SleepTracker = () => {
  const [data, setData] = useState({ x: 0, y: 0, z: 0 });
  const [subscription, setSubscription] = useState(null);

  const _subscribe = () => {
    setSubscription(
      Accelerometer.addListener(accelerometerData => {
        setData(accelerometerData);
      })
    );
    // Set the update interval for the accelerometer
    Accelerometer.setUpdateInterval(1000); // 1 second
  };

  const _unsubscribe = () => {
    subscription && subscription.remove();
    setSubscription(null);
  };

  useEffect(() => {
    _subscribe();
    return () => _unsubscribe();
  }, []);

  const { x, y, z } = data;
  return (
    <View style={styles.container}>
      <Text style={styles.text}>Accelerometer:</Text>
      <Text style={styles.text}>x: {Math.round(x)} y: {Math.round(y)} z: {Math.round(z)}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 18,
  },
});

export default SleepTracker;
Code collapsed

How it works

  • We import Accelerometer from expo-sensors.
  • The useEffect hook is used to subscribe to the accelerometer when the component mounts and unsubscribe when it unmounts. This is crucial to prevent memory leaks.
  • Accelerometer.addListener registers a callback function that receives the accelerometer data.
  • We store the latest sensor reading in the component's state using useState.

Step 2: Processing Movement Data

What we're doing

Raw x, y, and z values are hard to work with directly. We need a single value that represents the magnitude of movement. We can calculate this by finding the vector magnitude of the acceleration. This will give us a simple number that indicates how much the phone is moving.

Implementation

Let's modify our SleepTracker component to calculate and store the movement magnitude.

code
// src/components/SleepTracker.js (Updated)
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet, Button } from 'react-native';
import { Accelerometer } from 'expo-sensors';

const SleepTracker = () => {
  const [movementData, setMovementData] = useState([]);
  const [isTracking, setIsTracking] = useState(false);
  const [subscription, setSubscription] = useState(null);

  const startTracking = () => {
    setIsTracking(true);
    setSubscription(
      Accelerometer.addListener(({ x, y, z }) => {
        // Calculate magnitude of movement
        const magnitude = Math.sqrt(x ** 2 + y ** 2 + z ** 2);
        // We are interested in the change from the force of gravity (1)
        const movement = Math.abs(magnitude - 1);
        setMovementData(prevData => [...prevData, { movement, timestamp: new Date() }]);
      })
    );
    Accelerometer.setUpdateInterval(2000); // 2 seconds
  };

  const stopTracking = () => {
    setIsTracking(false);
    subscription && subscription.remove();
    setSubscription(null);
    // Here you would typically process the movementData
    console.log('Final Movement Data:', movementData);
  };

  useEffect(() => {
    return () => {
      subscription && subscription.remove();
    };
  }, [subscription]);

  return (
    <View style={styles.container}>
      <Text style={styles.text}>
        {isTracking ? 'Tracking Sleep...' : 'Ready to Track'}
      </Text>
      <Button title={isTracking ? "Stop Tracking" : "Start Tracking"} onPress={isTracking ? stopTracking : startTracking} />
    </View>
  );
};

// Styles remain the same
const styles = StyleSheet.create({
    container: {
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center',
    },
    text: {
      fontSize: 18,
      marginBottom: 20,
    },
  });

export default SleepTracker;
Code collapsed

How it works

  • We've added startTracking and stopTracking functions to control when we're collecting data.
  • Inside the accelerometer listener, we calculate the magnitude of the acceleration vector.
  • Since gravity exerts a force of approximately 1g, we subtract 1 from the magnitude to isolate movement. We take the absolute value as we're interested in any deviation.
  • Each movement value is stored with a timestamp in an array.

Step 3: The Smart Alarm Algorithm

What we're doing

This is the core logic of our smart alarm. The alarm will have a "wake-up window" (e.g., 30 minutes before the set alarm time). During this window, the app will monitor the user's movement. If the movement exceeds a certain threshold, indicating a light sleep phase, the alarm will sound.

Implementation

Let's create a new component for the alarm logic. For this example, we'll simulate the alarm window with a button press.

code
// src/components/SmartAlarm.js
import React, { useState, useEffect } from 'react';
import { View, Text, Button, Alert } from 'react-native';
import { Accelerometer } from 'expo-sensors';

const WAKE_UP_WINDOW_MINUTES = 30;
const MOVEMENT_THRESHOLD = 0.1; // This will need tuning

const SmartAlarm = () => {
  const [targetAlarmTime, setTargetAlarmTime] = useState(null);
  const [inWakeUpWindow, setInWakeUpWindow] = useState(false);
  const [subscription, setSubscription] = useState(null);

  useEffect(() => {
    // Check every second if we are in the wake up window
    const interval = setInterval(() => {
      if (targetAlarmTime) {
        const now = new Date();
        const windowStart = new Date(targetAlarmTime.getTime() - WAKE_UP_WINDOW_MINUTES * 60000);
        if (now >= windowStart && now <= targetAlarmTime) {
          if (!inWakeUpWindow) {
            console.log("Entering wake-up window. Starting to monitor for movement.");
            setInWakeUpWindow(true);
            startMonitoring();
          }
        } else if (now > targetAlarmTime) {
            console.log("Target alarm time passed. Firing alarm.");
            fireAlarm();
        }
      }
    }, 1000);

    return () => clearInterval(interval);
  }, [targetAlarmTime, inWakeUpWindow]);

  const setAlarm = () => {
    const targetTime = new Date();
    targetTime.setMinutes(targetTime.getMinutes() + 1); // For demo, set alarm 1 minute from now
    setTargetAlarmTime(targetTime);
    Alert.alert("Alarm Set", `Will look for light sleep between ${new Date(targetTime.getTime() - WAKE_UP_WINDOW_MINUTES * 60000).toLocaleTimeString()} and ${targetTime.toLocaleTimeString()}`);
  };

  const startMonitoring = () => {
    setSubscription(
      Accelerometer.addListener(({ x, y, z }) => {
        const magnitude = Math.sqrt(x ** 2 + y ** 2 + z ** 2);
        const movement = Math.abs(magnitude - 1);

        if (movement > MOVEMENT_THRESHOLD) {
          console.log(`Movement detected (${movement.toFixed(2)}). Firing smart alarm!`);
          fireAlarm();
        }
      })
    );
    Accelerometer.setUpdateInterval(2000);
  };

  const fireAlarm = () => {
    stopMonitoring();
    Alert.alert("Good Morning!", "Woke you up during a light sleep phase.");
    setTargetAlarmTime(null);
    setInWakeUpWindow(false);
  };

  const stopMonitoring = () => {
    subscription && subscription.remove();
    setSubscription(null);
  };

  return (
    <View>
      <Button title: "Set Smart Alarm for 1 Minute from Now" onPress={setAlarm} />
      {targetAlarmTime && <Text>Alarm set for: {targetAlarmTime.toLocaleTimeString()}</Text>}
    </View>
  );
};

export default SmartAlarm;
Code collapsed

How it works

  1. Setting the Alarm: The user sets a target time. We calculate a "wake-up window" that starts 30 minutes before this time.
  2. Entering the Window: A setInterval checks if the current time is within this window.
  3. Monitoring Movement: Once inside the window, we start listening to the accelerometer.
  4. Threshold Check: We calculate the movement magnitude. If it surpasses our MOVEMENT_THRESHOLD, it suggests the user is in a lighter sleep stage.
  5. Firing the Alarm: The alarm is triggered, and the monitoring stops.
  6. Failsafe: If no significant movement is detected by the target alarm time, the alarm goes off anyway.

Challenges and Considerations

  • Interpreting Sensor Data: The biggest challenge is the inherent noise in accelerometer data. A cough, a pet jumping on the bed, or the phone shifting can all create false positives. More sophisticated algorithms might use a moving average of movement to smooth out the data.
  • Threshold Tuning: The MOVEMENT_THRESHOLD is a critical value. It will vary depending on the phone's sensitivity, its placement on the bed, and the individual's sleep habits. A production-ready app would need a calibration phase.
  • Battery Life: Continuously polling the accelerometer can drain the battery. In a real app, you would use background processing and optimize the polling frequency.
  • Device Placement: The app's effectiveness depends on the phone being placed on the bed in a way that it can detect the user's movements.

Conclusion

We've successfully built the core of a "Smart Alarm" app in React Native. We learned how to access and process accelerometer data to estimate sleep phases and created an algorithm to wake a user during their lightest sleep. While this is a simplified implementation, it serves as a strong foundation for a more advanced sleep-tracking application.

The next steps could involve adding a user interface for setting alarms, persisting alarm data, and refining the sleep detection algorithm. This project demonstrates the exciting potential of using mobile sensors to create personalized health and wellness experiences.

Resources

Frequently Asked Questions

Q: How accurate is accelerometer-based sleep tracking compared to clinical sleep studies?

A: Accelerometer-based tracking provides a rough estimation of sleep patterns but is far less precise than clinical polysomnography. It can reliably distinguish between periods of movement and stillness but cannot detect REM sleep or brain activity patterns. For consumer wellness applications, this level of accuracy is generally sufficient, but it should not be used for medical diagnosis.

Q: Will this app drain my battery overnight?

A: The accelerometer is relatively power-efficient compared to other sensors like GPS or camera. However, continuous polling will consume some battery. In production apps, you would optimize by reducing the polling frequency during detected deep sleep periods and using background task APIs more efficiently.

Q: Can this work if I share the bed with a partner?

A: The app may detect movement from your partner as well as your own, potentially causing false positives. To mitigate this, you could add a sensitivity setting or focus the phone placement closer to your upper body where movements are more distinctive.

Q: What happens if I don't move at all during my wake-up window?

A: The app includes a failsafe mechanism where the alarm will fire at the target alarm time regardless of movement detection. This ensures you wake up on time even if the sleep tracking fails to detect a light sleep phase.

Q: Can I use this with a smartwatch instead of a phone?

A: Yes, the same principles apply to smartwatch accelerometers. In fact, wrist-based movement tracking can be more accurate for sleep detection since the device is securely attached to your body. You would adapt this code to run on watchOS or Wear OS using their respective sensor APIs.

Related Articles

#

Article Tags

reactnative
project
healthtech
datascience
W

WellAlly's core development team, comprised of healthcare professionals, software engineers, and UX designers committed to revolutionizing digital health management.

Expertise

Healthcare Technology
Software Development
User Experience
AI & Machine Learning

Found this article helpful?

Try KangXinBan and start your health management journey