Skip to content

Fix battery time-remaining on macOS 27 (IOPowerSources returns -1)#7

Open
heath-toby wants to merge 1 commit into
trypsynth:mainfrom
heath-toby:fix-battery-time-macos27
Open

Fix battery time-remaining on macOS 27 (IOPowerSources returns -1)#7
heath-toby wants to merge 1 commit into
trypsynth:mainfrom
heath-toby:fix-battery-time-macos27

Conversation

@heath-toby

Copy link
Copy Markdown

Summary

On macOS 27 beta the battery hotkey only ever announces "Calculating time until empty/full" — the time estimate never appears.

Cause

hs.battery.timeRemaining() / timeToFullCharge() read the high-level IOPowerSources API, which macOS 27 broke: it returns -1 ("no estimate"). pmset -g batt and Activity Monitor show the same "no estimate", so it is an OS-level regression, not a Hammerspoon one.

Fix

Layered, best source first — a no-op on macOS ≤ 26:

  1. Try the standard hs.battery API. On macOS ≤ 26 (and if Apple ever fixes 27) it returns a valid estimate and is used unchanged.
  2. On -1, read the battery firmware's own estimate from the raw AppleSmartBattery IORegistry node (AvgTimeToEmpty / AvgTimeToFull), which is still populated on 27.
  3. If even that is missing, compute independently from RemainingCapacity ÷ Amperage.

Also distinguishes actively Charging. from Plugged in, not charging. (e.g. sitting at an 80% charge limit).

Testing

Tested on macOS 27 beta (Apple Silicon): accurate times again (e.g. "9 hours, 7 minutes until empty"). Cross-checked the firmware estimate against the independent calc — within ~20 min of each other. readSmartBattery shells out to ioreg only when the API is actually broken.

🤖 Generated with Claude Code

On macOS 27 the high-level IOPowerSources API -- which hs.battery.timeRemaining()
and timeToFullCharge() (and pmset / Activity Monitor) rely on -- returns -1
("no estimate"), so the battery readout only ever said "Calculating time until
empty/full" and never gave a time.

The battery firmware's own estimate is still published in the raw
AppleSmartBattery IORegistry node, so fall back to that when the API returns -1,
and to an independent RemainingCapacity / Amperage calculation if even that is
missing. The standard API is still tried first, so behaviour is unchanged on
macOS <= 26 (and if Apple later fixes the API).

Also distinguishes actively "Charging." from "Plugged in, not charging." (e.g.
sitting at an 80% charge limit).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
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