Advertisement
Guest User

lm_sensors fan control script

a guest
Feb 3rd, 2016
31
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 7.28 KB | None | 0 0
  1. #!/bin/bash
  2.  
  3. # This script is intended to control the fan speeds on a Gigabyte Z77X-D3H
  4. # motherboard, while also using an NVIDIA GPU's temperature as input.
  5. #
  6. #
  7. # --------------------------------
  8. # Gigabyte GA-Z77X-D3H Motherboard
  9. # --------------------------------
  10. #
  11. # This board's sensors are at /sys/devices/platform/it87.2608/.
  12. #
  13. # pwm1 controls voltage of the CPU fan header (has to be disabled if using a PWM
  14. # fan).
  15. #
  16. # pwm2 controls the system fan headers (voltage on SYS_FAN1 and PWM on SYS_FAN[23]).
  17. #
  18. # pwm3 controls the PWM signal for the CPU fan header.
  19. #
  20. # temp1 is the "system" temperature.
  21. #
  22. # temp2 is the PCH's temperature.
  23. #
  24. # temp3 is the CPU temperature.
  25. #
  26. # Setting pwm2_enable to 0 disables control, will output a 100% voltage/PWM
  27. # signal.
  28. #
  29. # Setting pwm2_enable to 2 will cause the board's sensor chip logic to use some
  30. # sort of automatic to tie temperatures to fan speeds. The value in pwm2 seems
  31. # to be used as a multiplier for that automatic.
  32. #
  33. # Setting pwm2_enable to 1 will cause the chip to use a fixed speed as set in
  34. # pwm2. The value in pwm2 seems to have the value range of an unsigned 8-bit
  35. # number. The 0 to 255 value translates into a 0 to 100% fan speed signal.
  36. #
  37. #
  38. # ------------------
  39. # Intel i5-3570k CPU
  40. # ------------------
  41. #
  42. # The CPU's sensors are at /sys/devices/platform/coretemp.0/hwmon/hwmon0/.
  43. #
  44. # temp[2345] are the individual core temperatures.
  45. #
  46. # temp1 seems to be the highest core temperature.
  47. #
  48. #
  49. # -------------------------------
  50. # NVIDIA GPU, using NVIDIA's blob
  51. # -------------------------------
  52. #
  53. # There's no lm_sensors device.
  54. #
  55. # The nvidia-smi tool seems to be the least resource intensive method to read
  56. # temperatures from the card. The following outputs a single number (for GPU0)
  57. # in degrees Celsius (so without a factor of 1000 like lm_sensors):
  58. #
  59. # $ nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader --id=0
  60. #
  61.  
  62. # [ "$(whoami)" = root ] || exec sudo "$0"
  63.  
  64. pidfile="/var/run/fanauto.pid"
  65.  
  66. # Temperature limits in degrees Celsius:
  67. gpu_temp_to_sysfan_min=35
  68. gpu_temp_to_sysfan_max=65
  69.  
  70. cpu_temp_to_sysfan_min=30
  71. cpu_temp_to_sysfan_max=85
  72.  
  73. cpu_temp_to_cpufan_min=25
  74. cpu_temp_to_cpufan_max=75
  75.  
  76. # Fan speed limits in percent
  77. #
  78. # The script doesn't actually limit speeds at the max set here. The number is
  79. # only used for setting up the speed curve. It will go higher if the temperatures
  80. # are above max.
  81. sysfan_min=35
  82. sysfan_max=80
  83.  
  84. cpufan_min=30
  85. cpufan_max=80
  86.  
  87. # Fan speed history buffer length and update interval in seconds
  88. buf_length=40
  89. update_interval=3
  90.  
  91. # Number of intervals to skip after each output, so only outputs every 3+3*2=9 seconds
  92. output_skip=2
  93.  
  94. device_path="/sys/devices/platform/it87.2608"
  95.  
  96. # Temperature input
  97. function read_temperatures {
  98.   #read cpu_temp < /sys/devices/platform/coretemp.0/hwmon/hwmon0/temp1_input
  99.   read cpu_temp < $device_path/temp3_input
  100.   #read system_temp < $device_path/temp1_input
  101.   #read pch_temp < $device_path/temp2_input
  102.   gpu_temp=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader --id=0)000
  103. }
  104.  
  105. # Enable PWM control
  106. function enable_pwm {
  107.   echo 1 > $device_path/pwm2_enable
  108.   echo 1 > $device_path/pwm3_enable
  109. }
  110.  
  111. function output_pwm {
  112.   # $1: sysfan
  113.   # $2: cpufan
  114.   echo "$1" > $device_path/pwm2
  115.   echo "$2" > $device_path/pwm3
  116. }
  117.  
  118. # Save PWM setup
  119. function save_pwm {
  120.   read save_pwm2 < $device_path/pwm2
  121.   read save_pwm3 < $device_path/pwm3
  122.   read save_pwm2_enable < $device_path/pwm2_enable
  123.   read save_pwm3_enable < $device_path/pwm3_enable
  124. }
  125.  
  126.  
  127. # Restore PWM setup
  128. function restore_pwm {
  129.   enable_pwm
  130.   echo "$save_pwm2" > $device_path/pwm2
  131.   echo "$save_pwm3" > $device_path/pwm3
  132.   echo "$save_pwm2_enable" > $device_path/pwm2_enable
  133.   echo "$save_pwm3_enable" > $device_path/pwm3_enable
  134.   rm -f "$pidfile"
  135.   exit "$1"
  136. }
  137.  
  138. ######################################################
  139.  
  140. (( gpu_temp_to_sysfan_min *= 1000 ))
  141. (( gpu_temp_to_sysfan_max *= 1000 ))
  142. (( cpu_temp_to_sysfan_min *= 1000 ))
  143. (( cpu_temp_to_sysfan_max *= 1000 ))
  144. (( cpu_temp_to_cpufan_min *= 1000 ))
  145. (( cpu_temp_to_cpufan_max *= 1000 ))
  146. (( sysfan_min = sysfan_min * 1000 * 255 / 100 ))
  147. (( sysfan_max = sysfan_max * 1000 * 255 / 100 ))
  148. (( cpufan_min = cpufan_min * 1000 * 255 / 100 ))
  149. (( cpufan_max = cpufan_max * 1000 * 255 / 100 ))
  150. (( gpu_temp_to_sysfan_width = gpu_temp_to_sysfan_max - gpu_temp_to_sysfan_min ))
  151. (( cpu_temp_to_sysfan_width = cpu_temp_to_sysfan_max - cpu_temp_to_sysfan_min ))
  152. (( cpu_temp_to_cpufan_width = cpu_temp_to_cpufan_max - cpu_temp_to_cpufan_min ))
  153. (( sysfan_width = sysfan_max - sysfan_min ))
  154. (( cpufan_width = cpufan_max - cpufan_min ))
  155.  
  156. function calc_fan_speeds {
  157.   # translate both GPU and CPU temperature to system fan speed and use max
  158.   (( sysfan_gpu = (gpu_temp - gpu_temp_to_sysfan_min) * sysfan_width / gpu_temp_to_sysfan_width ))
  159.   (( sysfan_cpu = (cpu_temp - cpu_temp_to_sysfan_min) * sysfan_width / cpu_temp_to_sysfan_width ))
  160.  
  161.   # translate CPU temperature to CPU fan speed
  162.   (( cpufan_cpu = (cpu_temp - cpu_temp_to_cpufan_min) * cpufan_width / cpu_temp_to_cpufan_width ))
  163.  
  164.   # set correct minimum
  165.   sysfan=0
  166.   (( sysfan_gpu > sysfan )) && sysfan=$sysfan_gpu
  167.   (( sysfan_cpu > sysfan )) && sysfan=$sysfan_cpu
  168.   (( sysfan += sysfan_min ))
  169.  
  170.   cpufan=0
  171.   (( cpufan_cpu > cpufan )) && cpufan=$cpufan_cpu
  172.   (( cpufan += cpufan_min ))
  173. }
  174.  
  175. # set up a history of fan speeds that is intended to be used as a ring buffer
  176. cpufan_buf=()
  177. sysfan_buf=()
  178. buf_ringptr=0
  179. read_temperatures
  180. calc_fan_speeds
  181. for (( i = 0; i < buf_length; i++ ))
  182. do
  183.   (( sysfan_buf[i] = sysfan ))
  184.   (( cpufan_buf[i] = cpufan ))
  185. done
  186. (( sysfan_sum = sysfan * buf_length ))
  187. (( cpufan_sum = cpufan * buf_length ))
  188.  
  189. progname=$(basename "$0")
  190. if [[ -f "$pidfile" ]] ; then
  191.   echo "$progname: $pidfile exists" >&2
  192.   exit 1
  193. fi
  194. echo $$ > "$pidfile"
  195.  
  196. save_pwm
  197. trap 'restore_pwm 0' SIGQUIT SIGTERM
  198. trap 'restore_pwm 1' SIGHUP SIGINT EXIT
  199. enable_pwm
  200.  
  201. error_counter=0
  202. function error_handler {
  203.   (( error_counter++ ))
  204. }
  205. trap 'error_handler' ERR
  206.  
  207. # main loop
  208. output_limit_counter=0
  209. while true
  210. do
  211.  
  212.   read_temperatures
  213.   calc_fan_speeds
  214.  
  215.   (( sysfan_sum += sysfan - sysfan_buf[buf_ringptr] ))
  216.   (( cpufan_sum += cpufan - cpufan_buf[buf_ringptr] ))
  217.   (( sysfan_buf[buf_ringptr] = sysfan ))
  218.   (( cpufan_buf[buf_ringptr] = cpufan ))
  219.   (( ++buf_ringptr >= buf_length )) && buf_ringptr=0
  220.  
  221.   (( sysfan_out = (sysfan_sum / buf_length + 500) / 1000 )) # +500 to make rounding work
  222.   (( cpufan_out = (cpufan_sum / buf_length + 500) / 1000 ))
  223.   (( sysfan_out > 255 )) && sysfan_out=255
  224.   (( cpufan_out > 255 )) && cpufan_out=255
  225.  
  226.   # PWM output
  227.   if (( --output_limit_counter < 0 )) ; then
  228.     (( output_limit_counter = output_skip ))
  229.     output_pwm $sysfan_out $cpufan_out
  230.   fi
  231.  
  232.   if (( error_counter )) ; then
  233.     error_counter=0
  234.     enable_pwm # an error can happen after PC standby/resume, so trying to reenable pwm might work
  235.     if (( error_counter )) ; then
  236.       echo "something doesn't work!" >&2
  237.       exit 1
  238.     fi
  239.   fi    
  240.  
  241. #   echo cpu $((cpu_temp/1000))°C, gpu $((gpu_temp/1000))°C, \
  242. # cpu-fan $(((cpufan_out*1000+500)/2550))% \($(((cpufan+500)/2550))%\), \
  243. # sys-fan $(((sysfan_out*1000+500)/2550))% \($(((sysfan+500)/2550))%\)
  244.  
  245.   sleep $update_interval &
  246.   wait "$!"
  247.  
  248. done
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement