Skip to content

Add reachability (Auto) keep-awake mode + battery-floor safety - #49

Open
tomarai85 wants to merge 1 commit into
fuji-mak:mainfrom
tomarai85:feature/reachability-and-battery-floor
Open

Add reachability (Auto) keep-awake mode + battery-floor safety#49
tomarai85 wants to merge 1 commit into
fuji-mak:mainfrom
tomarai85:feature/reachability-and-battery-floor

Conversation

@tomarai85

Copy link
Copy Markdown

What

Two small, opt-in additions. Defaults are unchanged — with no configuration the app behaves exactly as it does today (Caps Lock keeps the Mac awake).

1. Keep-awake mode: Off / Caps Lock / Auto

Caps Lock stays the default and works exactly as today. Auto keeps the Mac awake automatically, independent of Caps Lock — for the case of closing the lid and driving the machine remotely (e.g. SSH from a phone), where you want it to stay reachable without remembering to toggle a key. Off is an explicit no-op.

2. Battery floor (opt-in, default 15%)

On battery, keep-awake is released at/below a threshold so the Mac can sleep before the battery fully drains — which, in the remote-use case, would also drop your access. It re-arms on AC, with hysteresis so it doesn't oscillate as the percentage jitters near the threshold.

Implementation notes:

  • BatteryReader reads the power source via IOKit (IOPSCopyPowerSourcesInfo) — no subprocess.
  • The decision is isolated in a pure BatteryFloorPolicy with 10 unit tests covering the floor boundary, the hysteresis latch, and the fail-safe cases (unreadable power → stay awake/reachable; on AC → keep; unknown percentage → keep).

Both are surfaced in the status menu (mode items + a Battery floor submenu) and the settings window, following the existing preference + localization patterns.

One small responsiveness change: the poll timer runs in .default instead of .common, so its periodic pmset -g verification never spawns a subprocess while a menu is being tracked.

Testing

swift test — all 24 tests green (14 existing + 10 new).

Notes

  • Fully backwards compatible; nothing changes unless you pick a non-default mode or enable the floor.
  • Happy to split this into two PRs (Auto mode / battery floor) if you'd rather review them independently, or to drop/adjust anything that doesn't fit Capsomnia's scope.

On battery, release the keep-awake assertion at or below a user-chosen
level so the Mac can sleep before the battery is fully drained. Off by
default; nothing changes unless it is turned on.

BatteryFloorPolicy.decide is a pure function with a recover margin so the
decision cannot flap around the threshold, and it is covered by 10 unit
tests. The IOKit power-source read is cached for 5s so the 250ms poll
does not spin it. Unreadable power state stays awake, so the floor can
never make behavior worse than today.

Menu: Battery floor > Off / 10% / 15% / 20% / 30%. Localized EN/JA/KO/zh-Hans.
@tomarai85
tomarai85 force-pushed the feature/reachability-and-battery-floor branch from 4ba23be to 7d90ff5 Compare July 30, 2026 00:19
@tomarai85

Copy link
Copy Markdown
Author

Rebased on current main. #41 landed the day after I opened this and overlapped with the keep-awake mode, so I dropped that half and kept only the battery floor.

Now +294/−1 across 4 files, down from +501/−22 across 7. Off by default — with no configuration the app behaves exactly as it does today.

BatteryFloorPolicy.decide is a pure function with a recover margin so it can't flap around the threshold; 10 unit tests cover it. The IOKit power-source read is cached for 5s so the 250ms poll doesn't spin it. Unreadable power state stays awake, so the floor can never make behavior worse than today.

The UI is a menu submenu (Battery floor ▸ Off / 10% / 15% / 20% / 30%), localized EN/JA/KO/zh-Hans. Happy to move it into Settings instead if you'd prefer it there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant