applemsc.sh
#!/bin/bash
#
# Author: $Author: smurphy $
# Locked by: $Locker:  $
#
# Programm Version
VER="$Revision: 1.17 $"
#
# Original author: Joerg Mertin <smurphy(-AT-)solsys.org>
# Enhancements by Wizardry and Steamworks <office(-AT-)grimore.org>
 
###########################################################################
##  Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3      ##
###########################################################################
function getCoreTemperatureFile {
    for i in /sys/devices/platform/coretemp.*/hwmon/hwmon*/*_label; do
        IFS=' ' read -ra CORE <<< `cat $i`
        if [ "${CORE[0]}" == "Core" ] && [ "${CORE[1]}" == $1 ]; then
            echo "${i//label/input}"
        fi
    done
}
 
# Get Program-Name, shortened Version.
PROGNAME="`basename $0 .sh`"
LockFile=/var/run/${PROGNAME}..LOCK
LOGGER=/usr/bin/logger
# Make sure that logger is not used if not found
if [ ! -x $LOGGER ] 
    then
    DOLOGGER=false || :
    echo "WARNING: $LOGGER program not found - syslog writing disabled"
else 
    DOLOGGER=true
fi
 
VERBOSE=true
POLL_TIME=10 # Poll interval, e.g. checking temperatures
DAEMON=false
SYSLOG=false
 
# User configurable part - files we find required informations
CPU_CORE0=$(getCoreTemperatureFile 0)
CPU_CORE1=$(getCoreTemperatureFile 1)
#FAN_SPEED=/sys/devices/platform/applesmc.768/fan1_input
FAN_SPEED=/sys/devices/platform/applesmc.768/fan1_min
FAN_SET=/sys/devices/platform/applesmc.768/fan1_output
FAN_MAN=/sys/devices/platform/applesmc.768/fan1_manual
 
# Some very conservative FAN speed settings
MIN_SPEED="`cat /sys/devices/platform/applesmc.768/fan1_min`"
#MIN_SPEED=2000 # If you want to override - here's your chance.
MAX_SPEED="`cat /sys/devices/platform/applesmc.768/fan1_max`"
# MAX_SPEED=6000 # If you want to override - here's your chance.
FAN_CHANGE=500
 
# Temperaturs
MAX_TEMP=80000
HIGH_TEMP=55000
LOW_TEMP=45000
 
###############################################################################
# Nothing to change below this point !
###############################################################################
 
 
 
##############################################################################
# Errors function
errors() {
#DOC: The errors Function is called to control the exit status.
#
: ${errlvl:=9}
: ${MSG:="No Error message - Probably user interruption"}
if [ $errlvl -gt 0 ] ;
    then
    if [ $errlvl = 15 ] ;
    then
        $VERBOSE && echo -e "WARNING: $MSG"
	log "WARNING: $MSG"
    else
        #Usage
        echo -e "\a"
        echo "FATAL:  An error occured in \"${PROGNAME}(${FUNCTION})\". Bailing out..."
        echo -e "ERRMSG: $MSG"
        echo
	fan_auto_operation auto
	log "FATAL: $MSG"
	Unlock $FLock
        exit $errlvl
    fi
fi
} # errors Function
#
#
##############################################################################
# Create Lockfile - prevent double start of app
Lock() {
# Lockfile to create
tolock="$1"
Action="$2"
#
# Lock file if lockfile does not exist.
if [ -s $tolock ]
then
    # If we have provided a second Var, set Exit status using  it.
    if [ ! -n "$Action" ]
    then
	# Oops, we  found a lockfile. Loop while checking if still exists.
	while [ -s $tolock ]
	do
	    sleep 5 ;
	done
	MSG="Creating lockfile $tolock failed after 5 secs"
	# write PID into Lock-File.
	if [ "$DAEMON" == "true" ]
	    then
	    echo $! > $tolock
	    errlvl=$?
	    errors
	else
	    echo $$ > $tolock
	    errlvl=$?
	    errors
	fi
    else
	Pid="`cat $tolock`"
	Exists="`ps auxw | grep \" $Pid \" | grep -c $PROGNAME`"
	if [ $Exists = 1 ]
	then
	    MSG="\"$PROGNAME\" already running. Exiting..."
	    errlvl=$Action
	    errors
	else
	    MSG="Found stale lockfile... Removing it..."
	    rm -f $tolock
	    errlvl=$?
	    errors
	    MSG="Creating lockfile $tolock failed"
   	    # write PID into Lock-File.
	    if [ "$DAEMON" == "true" ]
		then
		echo $! > $tolock
		errlvl=$?
		errors
	    else
		echo $$ > $tolock
		errlvl=$?
		errors
	    fi
	fi
    fi
else
    # write PID into Lock-File.
    MSG="Creating lockfile $tolock failed"
    if [ "$DAEMON" == "true" ]
	then
	echo $! > $tolock
	errlvl=$?
	errors
    else
	echo $$ > $tolock
	errlvl=$?
	errors
    fi
fi
} # Lock
#
##############################################################################
# Unlock lockfile
Unlock(){
# Name of Lockfile to unlock
unlock="$1"
# Unlock the file.
if [ -s $unlock ]
then
    if [ -n "$DPID" ]
	then
	PID=$DPID
    else
	PID=$$
    fi
 
    if [ "`cat $unlock`" -ne "$PID" ]
	then
        # Lock it
	echo -e "WARNING: Wrong lock-file PID. Probably a race-condition happened...\n"
    else
        # Removing Lockfile
	rm -f $unlock
    fi
fi
#
} # Unlock
#
###############################################################################
# Usage function - very small - just givs out some help.
 
usage() {
    echo "
Program: ${PROGNAME}.sh version $VER
         RCS$Id: applesmc.sh,v 1.17 2007/10/09 14:01:03 smurphy Exp $
         (c) J. Mertin <smurphy@solsys.org>
 
Usage: $0 [OPTION]...
 
Available options:
   -s     Status - just displays actual status informations
   -q     Quiet mode
   -v     Verbose mode
   -d     Daemon mode, go into background (implies -q)
   -k     Stop daemon
   -l     Log to syslog
"
    exit 1;
} # usage end.
 
#
###############################################################################
# Log function - very small
log() {
 
    # Be verbose
    ! $VERBOSE || echo "> $PROGNAME $*"
 
    # no logger found, no syslog capabilities
    if [ $DOLOGGER ]
	then
	! $SYSLOG || $LOGGER -t "$PROGNAME" "$*"
    fi
}
 
###############################################################################
# Get's CPU Temperature. In dual-core env - returns max temp detected
get_temp() {
    TEMP0=`cat $CPU_CORE0`
    TEMP1=`cat $CPU_CORE1`
    # Check max TEMP
    if [ $TEMP0 -gt $TEMP1 ] 
	then
	TEMP=$TEMP0
    else
	TEMP=$TEMP1
    fi
    let DTEMP=($TEMP / 1000)
} # get_temp
 
###############################################################################
# Get's the FAN Status
fan_status() {
    FSPEED=`cat $FAN_SPEED`
    let CHECK_SPEED=( $MIN_SPEED + $FAN_CHANGE )
 
    if [ $FSPEED -gt $CHECK_SPEED ]
	then 
	while [ $FSPEED -lt $CHECK_SPEED ]
	  do
	  if [ $CHECK_SPEED -ge $MAX_SPEED ] 
	      then
	      FSPEED=$MAX_SPEED
	      return
	  fi
	  let CHECK_SPEED=( $CHECK_SPEED + $FAN_CHANGE )
	done
	FSPEED=$CHECK_SPEED
    else
	FSPEED=$MIN_SPEED
    fi
 
    let SPEED_UP="( $FSPEED + $FAN_CHANGE )"
    let SPEED_DOWN="( $FSPEED - $FAN_CHANGE )"
} # fan_status
 
###############################################################################
# Sets the FAN Manual=1/Automatic=0 operation
# It will only be used in Daemon mode !
fan_auto_operation() {
    if [ "$*" == "auto" ]
	then
	log "Mode: auto - CPU ${DTEMP}C, FAN @ ${FSPEED}RPM"
	echo 0 > $FAN_MAN
    else
	log "Mode: manual - CPU ${DTEMP}C, FAN @ ${FSPEED}RPM"
	echo 1 > $FAN_MAN
    fi
    # Enter a little info the Logger
 
} # fan_auto_operation
 
###############################################################################
# Get's CPU Temperature. In dual-core env - returns max temp detected
do_status() {
    get_temp
    fan_status
    SPEED=`cat $FAN_SPEED`
    echo "Status: MAX Core Temp: ${DTEMP}C, FAN @ $SPEED / set ${FSPEED}RPM"
} # get_status
 
###############################################################################
# Get's CPU Temperature. In dual-core env - returns max temp detected
kill_daemon() {
 
    if [ -f "$LockFile" ]
	then
	set -e
	MSG="Extracting PID file of previous process"
	DPID="`cat \"$LockFile\"`" 
	errlvl=$?
	errors
	MSG="Killing PID $DPID failed"
	kill "$DPID"
	errlvl=$?
	errors
	log "Killed process $DPID"
        # Set fan operaion mode to auto
	fan_auto_operation auto
        # We need to remove lock file
	Unlock $LockFile
    else
 	log "No lockfile found. Bailing out"
    fi
} # kill_daemon
 
###############################################################################
# Main loop - the actuall working loop.
do_main() {
 
    # Enable the fan in default mode if anything goes wrong:
    set -e -E -u
    trap "errors; exit 2" HUP INT ABRT QUIT SEGV TERM
    trap "errors" EXIT
    trap "log 'Got SIGUSR1'; fan_auto_operation auto; " USR1
 
    # Get the actual Temp and Fan speed
    get_temp
    fan_status
 
    if [ "$DAEMON" == "true" ]
	then
	fan_auto_operation manual
    else
	fan_auto_operation auto
    fi
 
    while :;
      do
 
      # Get the actual Temp and Fan speed
      get_temp
      fan_status
 
      # Special case - if we have reached our set max temp - max FAN Speed !
      if [ $TEMP -gt $MAX_TEMP ]
	  then
	  if [ $MAX_SPEED -ne $FSPEED ]
	      then
	      echo $MAX_SPEED > $FAN_SET
	      log "CPU ${DTEMP}C, FAN @ ${FSPEED}RPM > ${MAX_SPEED}RPM"
	  fi
      elif [ $TEMP -gt $HIGH_TEMP ]
	  then
	  if [ $SPEED_UP -lt $MAX_SPEED ]
	      then
	      if [ $SPEED_UP -gt $FSPEED ]
		  then
		  echo $SPEED_UP > $FAN_SET
		  log "CPU ${DTEMP}C, FAN @ ${FSPEED}RPM > ${SPEED_UP}RPM"
	      fi
	  fi
      elif [ $TEMP -lt $LOW_TEMP ]
	  then
	  if [ $SPEED_DOWN -gt $MIN_SPEED ]
	      then
	      if [ $SPEED_DOWN -ne $FSPEED ]
		  then
		  echo $SPEED_DOWN > $FAN_SET
		  log "CPU ${DTEMP}C, FAN @ ${FSPEED}RPM > ${SPEED_DOWN}RPM"
	      fi
	  fi
      else 
	  if [ $MIN_SPEED -ne $FSPEED ]
	      then
	      echo $MIN_SPEED > $FAN_SET
	      log "CPU ${DTEMP}C, FAN @ ${FSPEED}RPM > ${MIN_SPEED}RPM"
	  fi
      fi
      if [ "$DAEMON" == "true" ]
	  then
	  sleep $POLL_TIME
      else
	  return
      fi
    done
 
} # do_main
 
#
###############################################################################
# Parse arguments
while getopts 'sqdlhkv' OPT; do
    case "$OPT" in
        s) # test mode
	    DAEMON=false
	    VERBOSE=true
	    SYSLOG=false
	    do_status
	    exit 0
            ;;
        d) # go into background and daemonize
	    DAEMON=true
	    VERBOSE=false
	    SYSLOG=true
            ;;
        q) # quiet mode
            VERBOSE=false
	    SYSLOG=true
            ;;
        k) # Kill daemon
	    DAEMON=false
	    VERBOSE=true
	    SYSLOG=true
	    log "Daemon shutdown requested"
	    get_temp
	    fan_status
	    kill_daemon
	    exit 0
            ;;
        l) # log to syslog
            SYSLOG=true
            ;;
        v) # log to syslog
            VERBOSE=true
            ;;
        h) # short help
            usage
	    exit 0
            ;;
        \?) # error
            usage
	    exit 0
            ;;
    esac
done
[ $OPTIND -gt $# ] || usage  # no non-option args
 
 
# That's the main loop.
if [ "$DAEMON" == "true" ]
then
    # We want to run as daemon - detach all from the console
    log "Version${VER} initialisation succeeded"
    Lock $LockFile 1
    do_main 0<&- 1>&- 2>&- &
    # Lock this process.
    DPID=$!
    echo $DPID > $LockFile
else 
    # Lock this process.
    Lock $LockFile 1
    # Normal run.
    do_main
    # Unlock the program.
    Unlock $LockFile
fi
 
exit 0

apple/macmini/fan_speed_control/applesmc.sh.txt ยท Last modified: 2022/04/19 08:28 by 127.0.0.1

Wizardry and Steamworks

© 2025 Wizardry and Steamworks

Access website using Tor Access website using i2p Wizardry and Steamworks PGP Key


For the contact, copyright, license, warranty and privacy terms for the usage of this website please see the contact, license, privacy, copyright.