Skip to content

Instantly share code, notes, and snippets.

@startergo
Last active February 15, 2026 18:46
Show Gist options
  • Select an option

  • Save startergo/ea6b825efd9846d989874bed1675a1e9 to your computer and use it in GitHub Desktop.

Select an option

Save startergo/ea6b825efd9846d989874bed1675a1e9 to your computer and use it in GitHub Desktop.
MacfansControl cMP5,1
Macs Fan Control 1.4.12
MacPro5,1
CPU: Intel(R) Xeon(R) CPU X5690 @ 3.47GHz [100]
GPU: Radeon RX 480 [active], Radeon RX 480
macOS 10.15.2

Fans:
PCI-min{800}curr{798}max{4500}mode{2,TA0P,32,40}
PS-min{600}curr{914}max{2800}mode{2,Tp1C,38,48}
EXHAUST-min{600}curr{599}max{2800}mode{0}
INTAKE-min{600}curr{1864}max{2800}mode{2,TN0D,53,63}
BOOSTA-min{800}curr{3168}max{5200}mode{2,TN0D,53,63}
BOOSTB-min{800}curr{1113}max{5200}mode{0}


TempSensors:
TA0P (Ambient) - 31.625, 31.625
TCAC (CPU A core from PCECI) - 41.3125, 58.6875
TCAD (CPU A Diode) - 43.25, 43.25
TCAG () - 80, 80
TCAH (CPU A HeatSink) - 39.75, 39.75
TCAS () - 39.75, 39.75
TCBC (CPU B core from PCECI) - 33.625, 66.375
TCBD (CPU B Diode) - 36.875, 36.875
TCBG () - 80, 80
TCBH (CPU B HeatSink) - 32.875, 32.875
TCBS () - 33, 33
TH1F () - 32.5391, 32.5391
TH1P (Drive Bay 0) - 32.5, 32.5
TH1V () - 35.2227, 35.2227
TH2F () - 34.1992, 34.1992
TH2P (Drive Bay 1) - 34.375, 34.375
TH2V () - 33.4062, 33.4062
TH3F () - 33.9375, 33.9375
TH3P (Drive Bay 2) - 34, 34
TH3V () - 32.8633, 32.8633
TH4F () - 33.082, 33.082
TH4P (Drive Bay 3) - 33.125, 33.125
TH4V () - 35.3047, 35.3047
THPS () - 35.2969, 35.2969
THTG () - 58, 58
TM1P (DIMM Proximity 1) - 36.5, 36.5
TM2P (DIMM Proximity 2) - 37.375, 37.375
TM3P (DIMM Proximity 3) - 38.625, 38.625
TM4P (DIMM Proximity 4) - 38.25, 38.25
TM5P (DIMM Proximity 5) - 38.5, 38.5
TM6P (DIMM Proximity 6) - 40.625, 40.625
TM7P (DIMM Proximity 7) - 37.5, 37.5
TM8P (DIMM Proximity 8) - 29.5, 29.5
TMA1 () - 40.75, 40.75
TMA2 () - 42.5, 42.5
TMA3 () - 42.75, 42.75
TMA4 () - 42.25, 42.25
TMB1 () - 34, 34
TMB2 () - 33.5, 33.5
TMB3 () - 33.75, 33.75
TMB4 () - 32, 32
TMHS () - 42.75, 42.75
TMLS () - 32, 32
TMPS () - 42.75, 42.75
TMPV () - 40.0859, 40.0859
TMTG () - 75, 75
TN0D (IOH Diode) - 59.25, 59.25
TN0H (IOH HeatSink) - 47.125, 47.125
TNTG () - 65, 65
Te1F () - 128, 128
Te1P (PCIE Ambient) - 34.375, 34.375
Te1S () - 128, 128
Te2F () - 129, 129
Te2S () - 129, 129
Te3F () - 129, 129
Te3S () - 129, 129
Te4F () - 129, 129
Te4S () - 129, 129
Te5F () - 129, 129
Te5S () - 129, 129
TeGG () - 85, 85
TeGP () - 0, 0
TeRG () - 60, 60
TeRP () - 0, 0
Tp0C (PSMI Supply AC/DC Supply 1) - 39.8125, 39.8125
Tp1C (PSMI Supply AC/DC Supply 2) - 40.3906, 40.3906
TpPS () - 40.3906, 40.3906
TpTG () - 90, 90
#/bin/bash
######################################################################################################################
# Bash script to control the three fans for an iMac 10,1 (late 2009) Intel Core Duo.
# Save somewhere like /usr/local/bin/fancontrol.sh
# sudo chmod 755 /usr/local/bin/fancontrol.sh
######################################################################################################################
######################################################################################################################
# To read internal drive temperature need to load the drivetemp module:
# Create file /etc/modules-load.d/drivetemp.conf with the text
# drivetemp
# For initial load:
# sudo modprobe drivetemp
######################################################################################################################
######################################################################################################################
# Create systemd service by writing /etc/systemd/system/fancontrol.service:
#
# [Unit]
# Description=Control iMac fans
#
# [Service]
# Type=simple
# ExecStart=/bin/bash /usr/local/bin/fancontrol.sh
#
# [Install]
# WantedBy=multi-user.target
#
# Then
# sudo systemctl enable fancontrol.service
# sudo systemctl start fancontrol.service
######################################################################################################################
######################################################################################################################
# The optical drive fan will be controlled by the GPU die temperature.
# The hard disk fan will be controlled by the SSD and memory temperatures, whichever is higher within its limits.
# The CPU fan will be controlled by the power supply and CPU core temperatures, whichever is higher within its limits.
######################################################################################################################
######################################################################################################################
# *_HIGH_TEMP variables contain the temperature in Celsius when the fan RPM will start to rise above the minimum.
# *_MAX_TEMP variables contain the temperature in Celsius when the fan will be running at maximum RPM.
######################################################################################################################
######################################################################################################################
# The sensors available on other iMac models will probably be different. Find the sensor names with:
# for sensor in /sys/devices/platform/applesmc.768/*_label; do echo -n $sensor " "; cat "$sensor"; done
# then an Internet search to identify what they mean.
######################################################################################################################
# Initial sleep so devices are present. I'm sure there's a better way of doing this.
sleep 10
# GPU die temp
GPU_TEMP_SENSOR=/sys/devices/platform/applesmc.768/temp6_input
GPU_HIGH_TEMP="82"
GPU_MAX_TEMP="100"
# Memory temp
MEM_TEMP_SENSOR=/sys/devices/platform/applesmc.768/temp26_input
MEM_HIGH_TEMP="65"
MEM_MAX_TEMP="85"
# SSD temp
# If you use /sys/class/hwmon you might find removable drives plugged in at boot time instead of the internal drive
# so look for ATA devices instead. Find the sensor path using:
# find /sys/devices -name hwmon -type d | grep ata1
SSD_TEMP_SENSOR_PATH="$(grep -l "drivetemp" /sys/devices/pci0000:00/0000:00:0b.0/ata1/host0/target0:0:0/0:0:0:0/hwmon/hwmon*/name)"
SSD_TEMP_SENSOR="${SSD_TEMP_SENSOR_PATH%/*}/temp1_input"
SSD_HIGH_TEMP="44"
SSD_MAX_TEMP="65"
# PSU temp
PSU_TEMP_SENSOR=/sys/devices/platform/applesmc.768/temp29_input
PSU_HIGH_TEMP="84"
PSU_MAX_TEMP="100"
# CPU temps
CPU_TEMP_SENSOR_PATH="$(grep -l "coretemp" /sys/class/hwmon/hwmon*/name)"
CPU1_TEMP_SENSOR="${CPU_TEMP_SENSOR_PATH%/*}/temp2_input"
CPU2_TEMP_SENSOR="${CPU_TEMP_SENSOR_PATH%/*}/temp3_input"
CPU_HIGH_TEMP="55"
CPU_MAX_TEMP="100"
# Fan devices
FAN_ODD_DEVICE=/sys/devices/platform/applesmc.768/fan1_
FAN_ODD_MIN=$(<"${FAN_ODD_DEVICE}min")
FAN_ODD_MAX=$(<"${FAN_ODD_DEVICE}max")
FAN_HDD_DEVICE=/sys/devices/platform/applesmc.768/fan2_
FAN_HDD_MIN=$(<"${FAN_HDD_DEVICE}min")
FAN_HDD_MAX=$(<"${FAN_HDD_DEVICE}max")
FAN_CPU_DEVICE=/sys/devices/platform/applesmc.768/fan3_
FAN_CPU_MIN=$(<"${FAN_CPU_DEVICE}min")
FAN_CPU_MAX=$(<"${FAN_CPU_DEVICE}max")
# Steps for fan when over the high temperature
GPU_FAN_STEP=$((($FAN_ODD_MAX - $FAN_ODD_MIN) / ($GPU_MAX_TEMP - $GPU_HIGH_TEMP)))
MEM_FAN_STEP=$((($FAN_HDD_MAX - $FAN_HDD_MIN) / ($MEM_MAX_TEMP - $MEM_HIGH_TEMP)))
SSD_FAN_STEP=$((($FAN_HDD_MAX - $FAN_HDD_MIN) / ($SSD_MAX_TEMP - $SSD_HIGH_TEMP)))
PSU_FAN_STEP=$((($FAN_CPU_MAX - $FAN_CPU_MIN) / ($PSU_MAX_TEMP - $PSU_HIGH_TEMP)))
CPU_FAN_STEP=$((($FAN_CPU_MAX - $FAN_CPU_MIN) / ($CPU_MAX_TEMP - $CPU_HIGH_TEMP)))
# Set manual fan mode
echo 1 > "${FAN_ODD_DEVICE}manual"
echo 1 > "${FAN_HDD_DEVICE}manual"
echo 1 > "${FAN_CPU_DEVICE}manual"
# Main loop
while true; do
GPU_TEMP=$(<"${GPU_TEMP_SENSOR}"); GPU_TEMP=$(($GPU_TEMP/1000))
MEM_TEMP=$(<"${MEM_TEMP_SENSOR}"); MEM_TEMP=$(($MEM_TEMP/1000))
SSD_TEMP=$(<"${SSD_TEMP_SENSOR}"); SSD_TEMP=$(($SSD_TEMP/1000))
PSU_TEMP=$(<"${PSU_TEMP_SENSOR}"); PSU_TEMP=$(($PSU_TEMP/1000))
CPU1_TEMP=$(<"${CPU1_TEMP_SENSOR}"); CPU1_TEMP=$(($CPU1_TEMP/1000))
CPU2_TEMP=$(<"${CPU2_TEMP_SENSOR}"); CPU2_TEMP=$(($CPU2_TEMP/1000))
# Work out fan speeds and test for sanity
GPU_FAN=$((($GPU_TEMP - $GPU_HIGH_TEMP) * $GPU_FAN_STEP + $FAN_ODD_MIN))
if [ "$GPU_FAN" -lt "$FAN_ODD_MIN" ] ; then GPU_FAN=$FAN_ODD_MIN ; fi
if [ "$GPU_FAN" -gt "$FAN_ODD_MAX" ] ; then GPU_FAN=$FAN_ODD_MAX ; fi
MEM_FAN=$((($MEM_TEMP - $MEM_HIGH_TEMP) * $MEM_FAN_STEP + $FAN_HDD_MIN))
if [ "$MEM_FAN" -lt "$FAN_HDD_MIN" ] ; then MEM_FAN=$FAN_HDD_MIN ; fi
if [ "$MEM_FAN" -gt "$FAN_HDD_MAX" ] ; then MEM_FAN=$FAN_HDD_MAX ; fi
SSD_FAN=$((($SSD_TEMP - $SSD_HIGH_TEMP) * $SSD_FAN_STEP + $FAN_HDD_MIN))
if [ "$SSD_FAN" -lt "$FAN_HDD_MIN" ] ; then SSD_FAN=$FAN_HDD_MIN ; fi
if [ "$SSD_FAN" -gt "$FAN_HDD_MAX" ] ; then SSD_FAN=$FAN_HDD_MAX ; fi
PSU_FAN=$((($PSU_TEMP - $PSU_HIGH_TEMP) * $PSU_FAN_STEP + $FAN_CPU_MIN))
if [ "$PSU_FAN" -lt "$FAN_CPU_MIN" ] ; then PSU_FAN=$FAN_CPU_MIN ; fi
if [ "$PSU_FAN" -gt "$FAN_CPU_MAX" ] ; then PSU_FAN=$FAN_CPU_MAX ; fi
CPU1_FAN=$((($CPU1_TEMP - $CPU_HIGH_TEMP) * $CPU_FAN_STEP + $FAN_CPU_MIN))
if [ "$CPU1_FAN" -lt "$FAN_CPU_MIN" ] ; then CPU1_FAN=$FAN_CPU_MIN ; fi
if [ "$CPU1_FAN" -gt "$FAN_CPU_MAX" ] ; then CPU1_FAN=$FAN_CPU_MAX ; fi
CPU2_FAN=$((($CPU2_TEMP - $CPU_HIGH_TEMP) * $CPU_FAN_STEP + $FAN_CPU_MIN))
if [ "$CPU2_FAN" -lt "$FAN_CPU_MIN" ] ; then CPU2_FAN=$FAN_CPU_MIN ; fi
if [ "$CPU2_FAN" -gt "$FAN_CPU_MAX" ] ; then CPU2_FAN=$FAN_CPU_MAX ; fi
# Set the fan speeds
ODD_FAN=$GPU_FAN
HDD_FAN=$MEM_FAN
if [ "$SSD_FAN" -gt "$HDD_FAN" ] ; then HDD_FAN=$SSD_FAN ; fi
CPU_FAN=$PSU_FAN
if [ "$CPU1_FAN" -gt "$CPU_FAN" ] ; then CPU_FAN=$CPU1_FAN ; fi
if [ "$CPU2_FAN" -gt "$CPU_FAN" ] ; then CPU_FAN=$CPU2_FAN ; fi
echo $ODD_FAN > "${FAN_ODD_DEVICE}output"
echo $HDD_FAN > "${FAN_HDD_DEVICE}output"
echo $CPU_FAN > "${FAN_CPU_DEVICE}output"
sleep 5
done
#!/usr/bin/env bash
# macpro-fancontrol.sh — configurable Mac Pro fan controller template
# Requires: an smc CLI tool in PATH. Configure READ/WRITE commands below.
# --- CONFIG: adapt these after we know your SMC keys ---
# Map of sensor keys to threshold (Celsius) and target fan RPM
# Example entries below are placeholders; replace keys after you supply `smc -l` output.
SENSORS=(
"TC0P:60:fan0:2500" # sensor_key:warn_temp_C:fan_id:target_rpm
"TG0D:70:fan1:3000"
)
# Fan control command placeholders:
# Replace these with the correct read/write commands for your `smc` binary.
SMC_READ() {
# usage: SMC_READ KEY
# Example: sudo smc -k "$1" -r
sudo smc -k "$1" -r 2>/dev/null
}
SMC_WRITE_RPM() {
# usage: SMC_WRITE_RPM FAN_ID RPM
# Example: sudo smc -k "F0Mn" -w 0x0BB8 (if your smc expects hex values)
# This is a placeholder — we'll adapt after you paste your smc output.
echo "WRITE: fan $1 -> $2 rpm (not yet implemented for this smc CLI)"
}
POLL_INTERVAL=10
# --- helpers ---
get_temp() {
key="$1"
out="$(SMC_READ "$key")"
# Attempt to extract float from output; adapt if your smc prints differently.
echo "$out" | grep -Eo '[0-9]+(\.[0-9]+)?' | head -1
}
set_fan() {
fan_id="$1"
rpm="$2"
SMC_WRITE_RPM "$fan_id" "$rpm"
}
# --- main loop ---
while true; do
now="$(date +'%Y-%m-%d %H:%M:%S')"
echo "[$now] checking sensors..."
for entry in "${SENSORS[@]}"; do
IFS=':' read -r skey thresh fanid target <<< "$entry"
temp="$(get_temp "$skey")"
if [ -z "$temp" ]; then
echo " $skey: read failed"
continue
fi
temp_int=${temp%.*}
echo " $skey -> ${temp}C (warn ${thresh}C) -> $fanid"
if [ "$temp_int" -ge "$thresh" ]; then
echo " threshold exceeded: setting $fanid -> ${target}rpm"
set_fan "$fanid" "$target"
fi
done
sleep "$POLL_INTERVAL"
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment