Fix Ftst key handling for Apple Silicon fan control#2924
Fix Ftst key handling for Apple Silicon fan control#2924agoodkind wants to merge 10 commits intoexelban:masterfrom
Ftst key handling for Apple Silicon fan control#2924Conversation
52e5f19 to
40540da
Compare
|
@exelban Here is a PR to add support for changing fan speeds on apple silicon |
d69e726 to
4adab44
Compare
|
Its very fanny to read PR called Please take a moment to review the project’s history. Much of what you’re implementing was already done 3–4 years ago, and the project has moved on since then because the original SMC implementation in C was not functioning correctly. |
4adab44 to
6d54758
Compare
Ftst key handling for Apple Silicon fan control
4bad4f6 to
39be0a7
Compare
There was a problem hiding this comment.
Bump is needed to make fan helper reinstall
39be0a7 to
15fcbcf
Compare
Hey thanks for the honest feedback, I appreciate you taking the time to review my PR. I reviewed the git history including the original C-based SMC code from 2020 (commit 413674d) and the Swift rewrite. You're right that I overcomplicated this. I tested the Swift struct layout using
So the C wrapper files I added were unnecessary and I've removed them. The existing Helper architecture (shelling out to the SMC CLI) works fine, and the refactor to move it into the program itself was out of scope. However, there's one piece that is new and required for Apple Silicon: the I've refactored the PR to be minimal:
Does this approach work for you? |
There was a problem hiding this comment.
The modified code was not rebuilding when I built the entire Stats target because Helper and SMC were not dependency targets
|
thx, looks much better now. Sorry but it will take some time to check everything. Please ping me if I will not provide any feedback to the end of next week. |
Thanks sounds good |
940988a to
1452aab
Compare
Signed-off-by: Alex Goodkind <alex@goodkind.io>
Signed-off-by: Alex Goodkind <alex@goodkind.io>
M1 Max/Ultra |
What happens if you try manually uninstalling and reinstalling the fan helper? |
|
will try later |
|
Okay sounds good, I’ll add some more logging too in a bit
…On Sun, Jan 25, 2026 at 08:44 Serhiy Mytrovtsiy ***@***.***> wrote:
*exelban* left a comment (exelban/stats#2924)
<#2924 (comment)>
will try later
—
Reply to this email directly, view it on GitHub
<#2924 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAHYOUDFGZBLQOOTTUAFQ5D4ITXFHAVCNFSM6AAAAACSWQM3ECVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTOOJWHEZDOMRTGI>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
|
|
and this is after manually uninstalling the fan helper from the settings
and then reinstalling from the menu bar?
…On Sun, Feb 1, 2026 at 09:07 Serhiy Mytrovtsiy ***@***.***> wrote:
*exelban* left a comment (exelban/stats#2924)
<#2924 (comment)>
[SMCHelper] setFanMode: fan=0, mode=1
[SMCHelper] setFanSpeed: fan=0, speed=3500
[SMCHelper] setFanMode result: [setFanMode] fan 0 -> manual
[Ftst] current value: 0, alreadyUnlocked: false
[Ftst] unlock (set to 1) failed after 10 attempts
[fan 0] FAILED to unlock fan control
[SMCHelper] setFanSpeed result: [setFanSpeed] fan 0 -> 3500 RPM
[Ftst] current value: 0, alreadyUnlocked: false
[Ftst] unlock (set to 1) failed after 10 attempts
Error: Failed to unlock fan 0 for speed change
[SMCHelper] setFanMode: fan=1, mode=1
[SMCHelper] setFanSpeed: fan=1, speed=3500
[SMCHelper] setFanMode result: [setFanMode] fan 1 -> manual
[Ftst] current value: 0, alreadyUnlocked: false
[Ftst] unlock (set to 1) failed after 10 attempts
[fan 1] FAILED to unlock fan control
[SMCHelper] setFanSpeed result: [setFanSpeed] fan 1 -> 3500 RPM
[Ftst] current value: 0, alreadyUnlocked: false
[Ftst] unlock (set to 1) failed after 10 attempts
Error: Failed to unlock fan 1 for speed change
—
Reply to this email directly, view it on GitHub
<#2924 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAHYOUATJLG3MVT3JLE57F34JYXDTAVCNFSM6AAAAACSWQM3ECVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTQMZRGQZTQNBQG4>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
|
yes, clean install |
|
That’s really odd, when I test it on a fresh install on my M3 and M4
MacBook pros it works really well
I don’t have an M1 to test with so it’s possible the unlock is different
for M1s
…On Sun, Feb 1, 2026 at 09:39 Serhiy Mytrovtsiy ***@***.***> wrote:
*exelban* left a comment (exelban/stats#2924)
<#2924 (comment)>
yes, clean install
—
Reply to this email directly, view it on GitHub
<#2924 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAHYOUDF663HKYGHP75LL234JY23VAVCNFSM6AAAAACSWQM3ECVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTQMZRGUZDQNRUGQ>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
|
You have an M1 Max is it a MacBook Pro or a Studio or a Mini?
…On Sun, Feb 1, 2026 at 09:56 Alex Goodkind ***@***.***> wrote:
That’s really odd, when I test it on a fresh install on my M3 and M4
MacBook pros it works really well
I don’t have an M1 to test with so it’s possible the unlock is different
for M1s
On Sun, Feb 1, 2026 at 09:39 Serhiy Mytrovtsiy ***@***.***>
wrote:
> *exelban* left a comment (exelban/stats#2924)
> <#2924 (comment)>
>
> yes, clean install
>
> —
> Reply to this email directly, view it on GitHub
> <#2924 (comment)>, or
> unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AAHYOUDF663HKYGHP75LL234JY23VAVCNFSM6AAAAACSWQM3ECVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTQMZRGUZDQNRUGQ>
> .
> You are receiving this because you authored the thread.Message ID:
> ***@***.***>
>
|
Signed-off-by: Alex Goodkind <alex@goodkind.io>
- Helper: serial queue for setFanMode/setFanSpeed/resetFanControl - smc.swift: 3s wait after Ftst=1, longer mode retry (100ms), SMC result logging - helpers: per-fan verification with cancel-on-supersede, clearer logs - smc.swift: neutral write logs (no 'succeeded'), FAILED on error
… (codes 4097 and 4099) during helper updates/restarts. - Removed unnecessary debug print statement in ModeButtons for improved log clarity.
|
@exelban Hey I dug into this a bit more. A few things were going on:
If you can try again with the latest changes (serialized ops, longer Ftst retry, 3s wait before mode write), that would help. If it still fails, the new logs should show the exact SMC result code so we can narrow it down further. Here is an example log of what my Mac does when I bump the helper (and the auto-reinstall occurs when I already had a manual speed set) |
…th, use isAutomatic in countManualFans; bump SMC Helper to 1.0.24
|
@exelban I managed to acquire an M1 MacBook pro and figured out the issue, been swamped with work but I'll put it up when I have a free moment this week |
Fixes #2928
Summary
On Apple Silicon,
thermalmonitordimmediately overrides writes toF0Md(mode) andF0Tg(target) unlessFtst=1is written first. The existing fan control implementation lacks this coordination, causing manual fan control to fail silently on M1/M2/M3 processors. This PR adds theFtstunlock/reset logic directly tosmc.swift, enabling fan control on Apple Silicon while preserving Intel compatibility.The implementation signals manual control intent via the
Ftstdiagnostic key, retries mode writes untilthermalmonitordreleases control, and properly resetsFtstwhen returning to automatic mode. Multi-fan scenarios are handled by only resettingFtstwhen all fans return to automatic.Demo
Screen.Recording.2026-01-23.at.13.33.26.mov
Screen.Recording.2026-01-23.at.13.32.06.mov
Testing
Mac16,6, MacBook Pro M4 Max) - fan speed changes take effectiMac19,1-FS!bitmask andfpe2format work correctly)References
Implementation based on macos-smc-fan, which provides detailed technical analysis of SMC fan control mechanisms on Apple Silicon.