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:

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:

  1. Create an IOHIDEventSystemClient
  2. Match services on PrimaryUsagePage: 0xff00 and PrimaryUsage: 5 — which targets the PMU temp sensors
  3. Enumerate each service, request a kIOHIDEventTypeTemperature event, extract the float value
  4. Filter out garbage values (anything outside 0–150°C)
  5. Output results in human-readable, --json, or --raw format
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.