Skip to content

2dubu/macfanctl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

macfanctl

CI

A macOS CLI for reading and controlling fan speeds via SMC.

Status

v0.1 — read + write both implemented and verified on MacBook Pro M5 Max / macOS 26.4. Other Apple Silicon generations are handled in code via the mode-key auto-probe but have not been hardware-tested by this project.

Requirements

  • Build targets macOS 13+. Tested on macOS 26.4.
  • MacBook Pro M5 Max verified. Other Macs may work but are unverified.

Install

Two steps: install the binary, then run setup to register a NOPASSWD sudoers rule so write commands run without a password prompt from your shell or any launcher.

Homebrew (Recommended)

brew install 2dubu/tap/macfanctl
sudo macfanctl setup

From source

git clone git@github.com:2dubu/macfanctl.git
cd macfanctl
make install     # builds release universal binary, ad-hoc signs, installs to /usr/local/bin
make setup       # same as `sudo macfanctl setup`

Uninstall

sudo macfanctl setup --uninstall && brew uninstall macfanctl

If installed from source instead of brew, replace brew uninstall macfanctl with sudo rm /usr/local/bin/macfanctl.

Usage

macfanctl list                       # show all fans (actual / min / max / target RPM)
macfanctl list --json                # machine-readable
macfanctl list --debug               # dump raw SMC fan key bytes (for diagnostics on new hardware)
macfanctl watch                      # live-refresh the fan table in place (like top); Ctrl+C to quit
macfanctl watch --interval 0.5       # refresh every 0.5s (default 1s)

sudo macfanctl set 3500              # set all fans to 3500 RPM
sudo macfanctl set 3500 --fan 0      # set fan 0 only
sudo macfanctl max                   # set all fans to their hardware maximum (per F%dMx)
sudo macfanctl max --fan 0           # set fan 0 only to max
sudo macfanctl auto                  # release all fans to system control
sudo macfanctl auto --fan 0          # release fan 0 only

set rejects RPM values above the fan's hardware max with a clear error rather than silently clamping. Use max if you want to push to the ceiling.

Without macfanctl setup, every write command will prompt for password. With it, the binary is allowed to run as root without prompting (scoped to /usr/local/bin/macfanctl only).

Raycast scripts

Optional Raycast Script Commands for one-keystroke fan control, available in raycast/:

  • fan-auto.sh — release all fans to system control (macfanctl auto)
  • fan-max.sh — push all fans to hardware maximum (macfanctl max)
  • fan-rpm.sh — set all fans to a specific RPM (prompts for an RPM argument)
  • fan-status.sh — show current fan state (RPM, min, max, target) via macfanctl list

Install

  1. In Raycast, open Settings → Extensions → Script Commands.
  2. Click Add Directories and select the raycast/ folder from this repo (or copy the .sh files into your existing Script Commands directory).

The scripts call sudo macfanctl … and rely on the NOPASSWD sudoers rule installed by macfanctl setup — without that step, Raycast has no way to provide a password and the write commands (fan-max, fan-rpm) will fail silently. fan-auto does not require root on every system but is invoked the same way for consistency.

Each script uses command -v macfanctl to locate the binary, so it works whether macfanctl was installed via Homebrew or built from source, as long as it's on PATH.

How it works

macfanctl talks to the AppleSMC IOKit service. The non-obvious part on Apple Silicon:

  1. Writes to the fan target key (F%dTg) succeed at the SMC interface (no error returned) but the written value does not stick — the system reasserts its own target almost immediately.
  2. The fix, per agoodkind/macos-smc-fan research, is to first write 1 to the fan mode key, which switches that fan from system-managed mode to manual mode. After that, F%dTg writes stick.
  3. The mode key casing varies by hardware: M5 uses F%dmd (lowercase, verified here). The research describes F%dMd (uppercase) for earlier generations. macfanctl probes both casings on the first write and caches the result.

References:

Architecture

  • SMCKit — Swift library wrapping AppleSMC IOKit service. Handles SMCParamStruct layout, key encoding (4-char FourCC), and value codecs (fpe2, flt, sp78, ui8, etc.).
  • macfanctlswift-argument-parser based CLI on top of SMCKit.

Write operations require root. The current MVP relies on a NOPASSWD sudoers rule. A privileged helper daemon for persistence is on the roadmap.

Limitations

  • Sleep/wake behavior not tested here. The agoodkind research notes that firmware resets the manual-mode unlock on sleep transitions; this project hasn't verified the behavior on M5 Max.
  • No Ftst diagnostic path. Per the research, some Apple Silicon generations require an Ftst=1 unlock dance before mode writes succeed. macfanctl currently only does the direct mode-write path (verified on M5).
  • F%dMn is read-only on M5. SMC returns 0x86 (key-not-writable) when attempting to write the minimum RPM. Informational — macfanctl doesn't touch Mn; switching to manual mode is what makes the target stick.

Reporting issues

If macfanctl doesn't work as expected on your Mac, please open a Hardware report. The output of macfanctl list --debug is the most useful single piece of data to include — it shows which SMC keys your hardware exposes.

License

MIT

About

A macOS CLI for reading and controlling fan speeds via SMC.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors