I’ve been working on a new iOS app called ZenMode—an automatic sleep tracker that uses your phone’s movement to detect when you’ve nodded off, log the session, and trigger things like Focus mode, all without taps.

No Apple Watch required. I ditched mine a while back—silicone bands, micro-plastics, and the hassle of wearing something all night. ZenMode runs just on the iPhone. Initial App Icon:

dro1d.org

Another reason for building it? I wanted a better alarm. One that looks good, has nice sounds, and doesn't feel like a shock every morning. The iOS default alarm UI and interface is soulless. I honestly hate the default Apple Alarm app. ZenMode's alarm UI will be clean, sound calm, and actually pleasant to wake up to.

dro1d.org

The Idea vs Reality

THE GOAL:

# Create a seamless, automatic sleep tracker using ONLY the phone. Minimal UI, 
maximum intelligence. User puts phone down, app detects stillness, sleep mode ON.
User picks up phone in the morning, sleep mode OFF.

Getting that kind of passive detection to work is tricky—especially without wrist-based data. The first big issue? Distinguishing when the phone itself is actually still, versus general inactivity in the room. iOS gives you tools like CMMotionActivityManager, but finding the right thresholds and timing—when the device isn’t attached to the user—took a lot of back-and-forth. Is the user asleep, or just watching something with their phone resting on the bed?

dro1d.org

$ Initial State
Just getting the basic UI and phone-based state management roughed out.

After plenty of testing, I settled on needing about 20 minutes of total stillness during a nightly window (say, 10 PM to 6 AM—customizable later). That’s when sleep mode will trigger. But the next hurdle was even bigger…

Wrangling Background Tasks & Concurrency

iOS BACKGROUND LIMITS:

# iOS is very strict about preserving battery life. Apps can’t run freely all night.
Keeping motion detection alive in the background means using Apple’s tools carefully.

This part’s still a work in progress. While CMMotionActivityManager is great, it tends to stop updating when the app is suspended. So how do you check for movement at 3 AM? BGTaskScheduler.

Setting this up involves:

Here’s a peek at what the registration looks like (simplified):

// dro1d:- Background Task Registration
func registerBackgroundTasks() {
	let taskID = "com.dro1d.checkStillness"
	BGTaskScheduler.shared.register(forTaskWithIdentifier: taskID, using: nil) { task in
		Task { await self.handleAppRefresh(task: task as! BGProcessingTask) }
	}
}

func scheduleAppRefresh() {
	let request = BGProcessingTaskRequest(identifier: taskID)
	request.earliestBeginDate = Date(timeIntervalSinceNow: 15 * 60)
	// Submit task to system...
}

Lots more testing ahead, still rough around the edges, most important is I want it to look perfect and function well.

dro1d.org