Getting CPU Temperature from the CLI on Apple Silicon
I wanted a simple way to get my Mac's CPU temperature from the command line — ideally something I could pipe into scripts and surface as a sensor in Home Assistant. What I assumed would be a five-minute task turned into a surprisingly deep rabbit hole that ended with me writing a native Objective-C tool from scratch.
Here's the full story.
The Dead Ends
osx-cpu-temp
The most commonly recommended tool for Mac CPU temps is osx-cpu-temp. It installs cleanly via Homebrew and the usage is dead simple:
brew install osx-cpu-temp
osx-cpu-temp
On Intel Macs, it works great. On Apple Silicon, it returns 0.0°C. The tool was built for Intel and reads from SMC keys that simply don't exist on M-series chips.
powermetrics
Apple ships a built-in tool called powermetrics that can sample various system metrics. Most guides suggest:
sudo powermetrics --samplers smc -i 1 -n 1 | grep -i temp
On recent macOS versions this returns:
powermetrics: unrecognized sampler: smc
Apple removed the SMC sampler. The replacement suggestion is --samplers thermal, which exists — but it only reports thermal pressure (whether the chip is throttling), not actual temperature values. A dead end.
mactop / asitop
Both mactop and asitop are TUI dashboard tools that do show real temperatures on Apple Silicon. The problem is they're designed for interactive use, not for piping. Neither has a --raw or --json output mode that works cleanly in scripts.
Finding the Right API
The key clue came from ioreg:
sudo ioreg -r -c AppleARMPMUTempSensor -l | head -100
This revealed that Apple Silicon Macs expose thermal sensors as AppleARMPMUTempSensor services, each with a Product name like PMU tcal, PMU tdev1, PMU tdev2, etc.
These aren't SMC key-value sensors at all. They're IOHIDEventService devices that deliver temperature readings as HID events via the private IOHIDEventSystem API.
The relevant private functions:
IOHIDEventSystemClientCreate— creates a client to the HID event systemIOHIDEventSystemClientSetMatching— filters to specific service typesIOHIDEventSystemClientCopyServices— enumerates matching servicesIOHIDServiceClientCopyEvent— requests a temperature event from a serviceIOHIDEventGetFloatValue— extracts the float value from the event
These functions exist in IOKit.framework but aren't exposed in public headers. They're accessible from Objective-C by declaring them yourself.
Building mac-temp
The tool is a single Objective-C file. The core logic:
- Create an
IOHIDEventSystemClient - Match services on
PrimaryUsagePage: 0xff00andPrimaryUsage: 5— which targets the PMU temp sensors - Enumerate each service, request a
kIOHIDEventTypeTemperatureevent, extract the float value - Filter out garbage values (anything outside 0–150°C)
- Output results in human-readable,
--json, or--rawformat
IOHIDEventSystemClientRef system = IOHIDEventSystemClientCreate(kCFAllocatorDefault);
NSDictionary *matching = @{
@"PrimaryUsagePage": @(0xff00),
@"PrimaryUsage": @(5)
};
IOHIDEventSystemClientSetMatching(system, (__bridge CFDictionaryRef)matching);
CFArrayRef services = IOHIDEventSystemClientCopyServices(system);
for (CFIndex i = 0; i < CFArrayGetCount(services); i++) {
IOHIDServiceClientRef service = (IOHIDServiceClientRef)CFArrayGetValueAtIndex(services, i);
IOHIDEventRef event = IOHIDServiceClientCopyEvent(service, kIOHIDEventTypeTemperature, 0, 0);
double temp = IOHIDEventGetFloatValue(event, kIOHIDEventFieldTemperatureLevel);
// ...
}
Compile with:
clang -fobjc-arc -framework Foundation -framework IOKit -o mac-temp mac-temp.m
No third-party dependencies. No Homebrew. Just Xcode Command Line Tools.
Usage
mac-temp # All sensors, human-readable
mac-temp --json # JSON output
mac-temp --raw # Single number, pipe-friendly
Example output:
PMU tcal 51.9°C
PMU tdev1 49.2°C
PMU tdev2 48.7°C
PMU tdev3 47.1°C
Notably, it doesn't require sudo — unlike most tools that read thermal data on Apple Silicon.
Signing and Notarizing for Distribution
Since the binary is distributed outside the App Store, it needs to be code-signed with a Developer ID certificate and notarized by Apple, otherwise users get the Gatekeeper malware warning.
Sign:
codesign --sign "Developer ID Application: Your Name (TEAMID)" \
--options runtime \
--timestamp \
mac-temp
Notarize:
zip mac-temp.zip mac-temp
xcrun notarytool submit mac-temp.zip \
--apple-id "you@email.com" \
--team-id "YOURTEAMID" \
--password "app-specific-password" \
--wait
One gotcha: stapling the notarization ticket (the usual final step) doesn't work on bare CLI binaries — xcrun stapler only supports .app bundles and .pkg installers. For a standalone binary, it doesn't matter. Gatekeeper verifies notarization online when the user first runs the tool, so the staple isn't required.
Wiring It Into Home Assistant
The original goal was to surface the temp as a Home Assistant sensor via the SSH integration. With mac-temp installed to /usr/local/bin, the sensor config is straightforward:
- command: /usr/local/bin/mac-temp --raw
scan_interval: 30
sensors:
- type: number
name: CPU temperature
key: cpu_temperature
float: true
unit_of_measurement: "°C"
Use the full path — SSH integrations often run in a restricted environment where /usr/local/bin isn't in PATH.
For Fahrenheit, use value_template:
- command: /usr/local/bin/mac-temp --raw
scan_interval: 30
sensors:
- type: number
name: CPU temperature
key: cpu_temperature
float: true
unit_of_measurement: "°F"
value_template: "{{ value | float * 9 / 5 + 32 }}"
The Code
The full source, Makefile, and pre-built universal binary are available on GitHub at zackwag/mac-temp.