DEV Community

Tuğberk Akbulut
Tuğberk Akbulut

Posted on

I built a terminal app to catch macOS dark wakes draining my MacBook's battery

A few days ago I opened my MacBook after it had been sitting closed for a while, and the battery was at 0%. Not a huge deal on its own, but it bothered me, the thing was closed, not doing anything, so where did the charge go?

I didn't really know where to start, so I asked an AI to help me dig into it. What we found was pretty eye-opening: over about a week, my Mac had 6 real user wake-ups vs. 1,342 dark wakes

What's actually happening

Turns out this is caused by Power Nap. While the machine looks fully asleep, macOS quietly wakes it up roughly every 15 minutes to sync mail, iCloud, and Calendar, and to run FileVault health checks. Each wake only lasts a couple of seconds, but multiply that by hundreds of times over several idle days and it adds up to a real chunk of battery. The laptop was never actually fully asleep, it was just pretending to be, most of the time.

I could've just flipped the Power Nap setting off in System Settings and moved on. But I wanted to actually see this happening instead of taking it on faith once and forgetting about it, and I wanted a way to keep an eye on it going forward, not just fix it once.

Building napwatch

So I built napwatch, a terminal app that watches for this continuously. It's written in Rust, using ratatui for the UI and crossterm for terminal handling.

The whole thing runs as one screen with three things visible at once:

  • What's eating power right now: processes ranked by actual Watts, accurate from the very first reading instead of waiting a few minutes for an average to settle.
  • Whether the machine is actually asleep: a live, color-coded feed of Sleep / DarkWake / Wake events as they happen. Turning Power Nap off and watching the DarkWake entries stop appearing in real time was oddly satisfying the first time I tried it.
  • Which power settings are currently on: Power Nap, Low Power Mode, Standby, Wake-on-LAN, TCP Keepalive: and you can toggle any of them right from the app instead of digging through System Settings.

There's also a detail view for any process (full path, parent process, launchd label, app bundle info if it's a bundled app), and you can terminate or renice a process without leaving the terminal.

How it gets its data

Nothing here talks to a private API. It's all standard macOS command-line tools, shelled out to and parsed:

Source Used for
pmset -g batt Battery percentage, charging state, time remaining
pmset -g stats Lifetime sleep/dark-wake/user-wake counts
pmset -g log Sleep/wake event history for the live feed
ioreg -rn AppleSmartBattery Instant amperage/voltage/capacity for the real-time Watts figure
top -l 2 -o power Per-process energy-impact ranking
ps / launchctl list / plutil -extract Process detail and app bundle info

A couple of things worth calling out from actually building this:

  • Instant power draw is trickier than it sounds. An earlier version tried to derive a drain rate from whole-percentage battery deltas over a rolling window, which meant waiting a few minutes before the number meant anything. Computing it from ioreg's instant amperage/voltage/capacity fields instead gives a correct number from the first poll.
  • top -l 1 always reads 0 for every process. Power is a rate, so it needs a delta between two samples. napwatch runs top -l 2 and only keeps the second sample.
  • pmset -g log has no since/tail flag — it always dumps the entire history, which gets slow once the log has days of entries in it. So it's polled on its own slower cadence rather than every tick, and the live feed seeds with just the last few historical events on startup instead of replaying everything.

Trying it out

It's macOS only, and installable via Homebrew:

brew install Tuguberk/napwatch/napwatch
Enter fullscreen mode Exit fullscreen mode

Or build from source if you have Rust installed:

git clone https://github.com/Tuguberk/napwatch.git
cd napwatch
cargo install --path .
Enter fullscreen mode Exit fullscreen mode

It's fully open source under MIT: github.com/Tuguberk/napwatch

If your Mac's battery has ever done something similarly weird while "asleep," I'd be curious whether you're seeing the same dark-wake pattern. And if you find it useful, a star on the repo is always appreciated.

Top comments (0)