fix(helper): hand fans to macOS auto on system sleep (#2) - #3
Merged
Conversation
When the Mac sleeps, the SMC keeps honoring Mystral's last forced fan mode + RPM (the app's poll loop is suspended), so the fan keeps spinning and whines. The root helper now registers for IOKit system-power notifications and, on kIOMessageSystemWillSleep, releases forced mode so the firmware idles the fans; it always acks via IOAllowPowerChange to avoid the ~30s sleep stall. Wake re-applies the curve via the app's existing handleWake. Routing is factored into a unit-tested handlePowerMessage(); the C callback is a thin shell. SIGTERM reuses the shared restoreAutoMode(). Closes #2
There was a problem hiding this comment.
Pull request overview
This PR updates the root helper to listen for IOKit system-power sleep notifications and, on kIOMessageSystemWillSleep, release forced fan control back to macOS auto mode so the SMC firmware can idle fans during sleep (issue #2). It also adds unit tests validating the message routing and auto-restore behavior using the real IOKit ABI message values, plus supporting documentation and a version bump.
Changes:
- Register the helper for IOKit sleep notifications and restore auto fan mode pre-sleep (with an ack requirement handled in the callback).
- Add unit tests for
restoreAutoModeandhandlePowerMessage, including mock tracking forsetForcedMode. - Add an approved design spec and bump the app version/build number.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| Mystral/Services/SMCHelperMode.swift | Adds IOKit power-notification registration, routes sleep messages to auto-restore, and a C callback to ack sleep transitions. |
| MystralTests/SMCServiceTests.swift | Extends the mock to record forced-mode calls and adds 4 unit tests covering sleep routing/restore behavior. |
| Mystral/Info.plist | Bumps CFBundleShortVersionString and CFBundleVersion. |
| docs/superpowers/specs/2026-06-08-quiet-fans-on-sleep-design.md | Adds the design spec for quiet fans on sleep. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+290
to
+297
| private func mystralSleepWakeCallback(_ refcon: UnsafeMutableRawPointer?, | ||
| _ service: io_service_t, | ||
| _ messageType: UInt32, | ||
| _ messageArgument: UnsafeMutableRawPointer?) { | ||
| if SMCHelperMode.handlePowerMessage(messageType, smc: SMCHelperMode.powerSMC) { | ||
| IOAllowPowerChange(SMCHelperMode.rootPowerPort, Int(bitPattern: messageArgument)) | ||
| } | ||
| } |
Comment on lines
+149
to
+151
| static func restoreAutoMode(smc: SMCServiceProtocol) { | ||
| let count = (try? smc.getAllFans().count) ?? 2 | ||
| try? smc.setForcedMode(fanCount: count, forced: false) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
On system sleep the root helper registers for IOKit system-power notifications and, on
kIOMessageSystemWillSleep, hands fan control back to macOS auto mode (setForcedMode(forced: false)). The SMC firmware then idles the fans during sleep instead of holding the last forced RPM. On wake the app re-applies its curve (already handled).Changes are confined to
SMCHelperMode.swiftplus a test-only mock extension. Design spec:docs/superpowers/specs/2026-06-08-quiet-fans-on-sleep-design.md.Tests
4 unit tests cover the routing (
handlePowerMessage) andrestoreAutoModeagainst the real IOKit ABI message numbers.Closes #2.
🤖 Generated with Claude Code