#!/bin/sh # monitor temperature on external Quadro NVS420 and adjust fan speed # logs changes to syslog # Copyright 2015 TJ # Licenced on the terms of the GNU General Public Licence version 3 # uncomment for debugging in foreground # set -x # user-friendly device name for logging TARGET=${TARGET:-NVS420} # GPUs reported by nvidia-settings GPU_CONTROL=${GPU_CONTROL:-1 2} # Fans reported FAN_CONTROL=${FAN_CONTROL:-0} # temperature bounds TARGET_TEMP_MIN=${TARGET_TEMP_MIN:-60} TARGET_TEMP_RANGE=${TARGET_TEMP_RANGE:-5} TARGET_TEMP_MAX=${TARGET_TEMP_MAX:-$((TARGET_TEMP_MIN + TARGET_TEMP_RANGE))} # sampling delay in seconds SLEEP=${SLEEP:-2} # percentages FAN_SPEED_MAX=${FAN_SPEED_MAX:-100} FAN_SPEED_MIN=${FAN_SPEED_MIN:-30} FAN_SPEED_STEP_BASE=${FAN_SPEED_STEP_BASE:-5} FAN_SPEED_STEP=${FAN_SPEED_STEP_BASE} # maximum speed change in one operation FAN_SPEED_STEP_MAX=$(( (FAN_SPEED_MAX - FAN_SPEED_STEP_MIN) / 4 )) TEMP_LAST=0 NO_CHANGE_COUNT=0 # adjust fan speed in proportion to temperature differential adjust_proportional () { TEMP_DIFF=$(( TEMP_AVG - TARGET_TEMP_MIN )) TEMP_CHANGE=$(( TEMP_AVG - TEMP_LAST )) # shell doesn't allow return values < 0 so bias to 128 and remember to remove bias in calling code return $(( TEMP_CHANGE * TEMP_DIFF + $1 + TEMP_DIFF + 128 )) } # start logger -p syslog.notice -- nvidia_fan_control[$$]: ${TARGET} Target ${TARGET_TEMP_MIN}-${TARGET_TEMP_MAX}°C controlling GPUs: ${GPU_CONTROL} Fans: ${FAN_CONTROL} # continue looping whilst the X server is running while pgrep X; do TEMP_AVG=0 GPU_COUNT=0 for GPU in ${GPU_CONTROL}; do TEMP_AVG=$(( TEMP_AVG + $(nvidia-settings --terse --query [gpu:${GPU}]/GPUCoreTemp) )) done TEMP_AVG=$(( TEMP_AVG/2 )) for FAN in ${FAN_CONTROL}; do FAN_SPEED=$(nvidia-settings --terse --query [fan:${FAN}]/GPUTargetFanSpeed) if [ -n "${TEMP_AVG}" -a -n "${FAN_SPEED}" ]; then FAN_SPEED_NEW=${FAN_SPEED} # call adjustment calculation function if [ ${TEMP_LAST} -gt 0 ]; then adjust_proportional ${FAN_SPEED} FAN_SPEED_NEW=$(( $? - 128)) fi if [ ${FAN_SPEED_NEW} -gt ${FAN_SPEED_MAX} ]; then FAN_SPEED_NEW=${FAN_SPEED_MAX} elif [ ${FAN_SPEED_NEW} -lt ${FAN_SPEED_MIN} ]; then FAN_SPEED_NEW=${FAN_SPEED_MIN} fi if [ ${FAN_SPEED} -ne ${FAN_SPEED_NEW} ]; then for GPU in ${GPU_CONTROL}; do nvidia-settings --verbose=none --assign=[gpu:${GPU}]/GPUFanControlState=1 >/dev/null done nvidia-settings --verbose=none --assign=[fan:${FAN}]/GPUTargetFanSpeed=${FAN_SPEED_NEW} >/dev/null logger -p syslog.notice -- nvidia_fan_control[$$]: ${TARGET} Target ${TARGET_TEMP_MIN}-${TARGET_TEMP_MAX}°C Temp=${TEMP_AVG}°C Fan=${FAN_SPEED_NEW}% fi fi done TEMP_LAST=${TEMP_AVG} sleep ${SLEEP} done