Controlar las RPM de los ventiladores en Unraid (II)

2024-11-25

Ya vimos como controlar las RPM de los ventiladores de nuestro ordenador en Unraid mediante el uso de los plugins de Dymamix, pero esto no siempre funciona o funciona a medias, es por ello por lo que mediante el uso de un par de sencillos scripts podemos llegar controlarlos de una manera muy parecida.

⚠️ Hay que configurar en la BIOS de la placa base que el control de la temperatura de los sensores se va a realizar por software

Para hacer uso de los scripts es necesarios que tengas instalado el plugin User Scripts

Hay que identificar los sensores que se corresponden con cada ventilador, para ello y tal como expliqué en este otro articulo hacemos uso de pwmconfig desde una consola

root@Nas01:~# pwmconfig
# pwmconfig version 3.6.0
This program will search your sensors for pulse width modulation (pwm)
controls, and test each one to see if it controls a fan on
your motherboard. Note that many motherboards do not have pwm
circuitry installed, even if your sensor chip supports pwm.

We will attempt to briefly stop each fan using the pwm controls.
The program will attempt to restore each fan to full speed
after testing. However, it is ** very important ** that you
physically verify that the fans have been to full speed
after the program has completed.

Found the following devices:
   hwmon0 is acpitz
   hwmon1 is nvme
   hwmon2 is nvme
   hwmon3 is eth1
   hwmon4 is coretemp
   hwmon5 is it8613

Found the following PWM controls:
   hwmon5/pwm2           current value: 60
   hwmon5/pwm3           current value: 106
   hwmon5/pwm4           current value: 0
   hwmon5/pwm5           current value: 60

Giving the fans some time to reach full speed...
Found the following fan sensors:
   hwmon5/fan2_input     current speed: 5000 RPM
   hwmon5/fan3_input     current speed: 2109 RPM

Warning!!! This program will stop your fans, one at a time,
for approximately 5 seconds each!!!
This may cause your processor temperature to rise!!!
If you do not want to do this hit control-C now!!!
Hit return to continue:

Como ves, entre los dispositivos detectados ha encontrado hwmon4 is coretemp y hwmon5 is it8613 y los sensores PWM con ventiladores conectados hwmon5/fan2_input y hwmon5/fan3_input

Puedes determinar cual se corresponde con el la CPU y cual con el de la caja, parando o poniendo al máximo las RPM del ventilador, por ejemplo para pleno funcionamiento

echo 255 > /sys/class/hwmon/hwmon5/pwm3

Para pararlo

echo 0 > /sys/class/hwmon/hwmon5/pwm3

En mi ordenador el sensor pwm3 controla el ventilador de la caja y el el pwm2 la cpu

Una vez que tenemos claro que sensor se corresponde con cada ventilador procedemos a crear un script para controlar las RPM del ventilador de la CPU y otro script para conrolar las RPM del ventilador de la caja en función de la temperatura de los discos desde el plugin User Scripts

Script para controlar las RPM del ventilador de la CPU

#!/bin/bash

    TEMPS=(0 40 55 75 80)
    SPEEDS=(60 90 130 190 255)
    # Fan device. Depends on your system. pwmconfig can help with finding this out.
    # pwm1 is usually the cpu fan. You can "cat /sys/class/hwmon/hwmon0/device/fan1_input"
    # or fan2_input and so on to see the current rpm of the fan. If 0 then fan is off or
    # there is no fan connected or motherboard can't read rpm of fan.
    CPU_FAN=/sys/class/hwmon/hwmon5/pwm2


    #REPLACE HD TEMP WITH CPU TEMP FROM SENSORS
    HIGHEST_TEMP=$(/usr/bin/sensors | grep "CPU Temp" | cut -d"+" -f2 | cut -c1-2)


    for i in ${!TEMPS[@]}; do
        CHECKTEMP=${TEMPS[$i]}
        #echo "loop " $i $CHECKTEMP
        if [ "$HIGHEST_TEMP" -le "$CHECKTEMP" ]; then
            break
        fi
        LASTTEMP=${TEMPS[$i]}
        FANSET=${SPEEDS[$i]}
    done
    echo "Temp " $HIGHEST_TEMP " >= " $LASTTEMP "Setting fan to " $FANSET
    echo $FANSET > $CPU_FAN

Aquí tienes que jugar con los ajustes de temperatura y las RPM a las que quieres que funcione el ventilador, con las variables TEMPS y SPEEDS

🗨️ CPU_FAN es el sensor que va a controlar el ventilador, aquí debes de poner el que se corresponda con el tuyo.

Comprueba que el script se ejecuta sin errores

Configura el script para que se ejecute cada minuto

No olvides aplicar los cambios

Script para controlar las RPM del ventilador de la caja

El siguiente script controla la velocidad del ventilador de la caja en funcion de la temperatura del array de los discos.

#!/bin/bash

# This script will automatically adjust the fans speed
# based on your hard drives temperature. You may select
# which disks to include and exclude and play around with
# different temperature settings.

# Prerequisites:
# 1. Enable manual fan speed control in Unraid
#    This can be done by editing "/boot/syslinux/syslinux.cfg"
#    Right beneath "label Unraid OS" you will have to change:
#    "append initrd=/bzroot" to "append initrd=/bzroot acpi_enforce_resources=lax"
# 2. Set the PWM headers you want to control to 100%/255 and mode to PWM in your BIOS

# Tips:
# In order to see what fan headers Unraid sees use "sensors -uA"
# Another useful tool is "pwmconfig". Makes it easier to find the correct fan header
# You may test your pwm pins from the terminal. Here is a list of attributes:
# pwm[1-5] - this file stores PWM duty cycle or DC value (fan speed) in range:
#     0 (lowest speed) to 255 (full)
# pwm[1-5]_enable - this file controls mode of fan/temperature control:
#   * 0 Fan control disabled (fans set to maximum speed)
#   * 1 Manual mode, write to pwm[0-5] any value 0-255
#   * 2 "Thermal Cruise" mode
#   * 3 "Fan Speed Cruise" mode
#   * 4 "Smart Fan III" mode (NCT6775F only)
#   * 5 "Smart Fan IV" mode
# pwm[1-5]_mode - controls if output is PWM or DC level
#   * 0 DC output
#   * 1 PWM output

# Minimum PWM value
# Used when all disks are spun down
# and fan speed will never be set to a lower value
MIN_PWM=40

# Low/High PWM values
# Used for calculating new PWM values when
# disk temp is between LOW_TEMP and HIGH_TEMP temperature
LOW_PWM=60
HIGH_PWM=225

# Max PWM
# Used for setting the fan to max speed while parity
# is running or if the disk temperature is too hot
# This settings should in most cases NOT BE CHANGED!
MAX_PWM=255

# Low/High temperature
# Define the disks temperature range for when
# the fans speed should be automatically adjusted
#LOW_TEMP=35
LOW_TEMP=40
HIGH_TEMP=50

# Max temperature
# If the hottest disk reaches this temperature
# a notification will be sent through Unraid
MAX_TEMP=55

# Disks to monitor
# Select disks to include by type and
# exclude by name (found in disk.ini)
INCLUDE_DISK_TYPE_PARITY=1
INCLUDE_DISK_TYPE_DATA=1
INCLUDE_DISK_TYPE_CACHE=0
INCLUDE_DISK_TYPE_FLASH=0
EXCLUDE_DISK_BY_NAME=(
    "cache"
    "sistema"
    "sistema2"
)

# Array fans
# Define one or more fans that should be controlled by this script
ARRAY_FANS=(
        "/sys/class/hwmon/hwmon5/pwm3"
)

############################################################


# Make a list of disk types the user wants to monitor
declare -A include_disk_types
include_disk_types[Parity]=$INCLUDE_DISK_TYPE_PARITY
include_disk_types[Data]=$INCLUDE_DISK_TYPE_DATA
include_disk_types[Cache]=$INCLUDE_DISK_TYPE_CACHE
include_disk_types[Flash]=$INCLUDE_DISK_TYPE_FLASH

# Make a list of all the existing disks
declare -a disk_list_all
while IFS='= ' read var val
do
    if [[ $var == \[*] ]]
    then
        disk_name=${var:2:-2}
        disk_list_all+=($disk_name)
        eval declare -A ${disk_name}_data
    elif [[ $val ]]
    then
        eval ${disk_name}_data[$var]=$val
    fi
done < /var/local/emhttp/disks.ini

# Filter disk list based on criteria
declare -a disk_list
for disk in "${disk_list_all[@]}"
do
    disk_name=${disk}_data[name]
    disk_type=${disk}_data[type]
    disk_id=${disk}_data[id]
    disk_type_filter=${include_disk_types[${!disk_type}]}

    if [[ ! -z "${!disk_id}" ]] && \
       [[ "${disk_type_filter}" -ne 0 ]] && \
       [[ ! " ${EXCLUDE_DISK_BY_NAME[*]} " =~ " ${disk} " ]]
    then
        disk_list+=($disk)
    fi
done

# Check temperature
declare -A disk_state
declare -A disk_temp
disk_max_temp_value=0
disk_max_temp_name=null
disk_active_num=0

for disk in "${disk_list[@]}"
do
    # Check disk state
    eval state_value=${disk}_data[spundown]
    if (( ${state_value} == 1 ))
    then
        state=spundown
        disk_state[${disk}]=spundown
    else
        state=spunup
        disk_state[${disk}]=spunup
        disk_active_num=$((disk_active_num+1))
    fi

    # Check disk temperature
    temp=${disk}_data[temp]
    if [[ "$state" == "spunup" ]]
    then
        if [[ "${!temp}" =~ ^[0-9]+$ ]]
        then
            disk_temp[${disk}]=${!temp}
            if (( "${!temp}" > "$disk_max_temp_value" ))
            then
                disk_max_temp_value=${!temp}
                disk_max_temp_name=$disk
            fi
        else
            disk_temp[$disk]=unknown
        fi
    else
        disk_temp[$disk]=na
    fi
done


# Check if parity is running
disk_parity=$(awk -F'=' '$1=="mdResync" {gsub(/"/, "", $2); print $2}' /var/local/emhttp/var.ini)

# Linear PWM Logic
pwm_steps=$((HIGH_TEMP - LOW_TEMP - 1))
pwm_increment=$(( (HIGH_PWM - LOW_PWM) / pwm_steps))

# Print heighest disk temp if at least one is active
if [[ $disk_active_num -gt 0 ]]; then
    echo "Hottest disk is $disk_max_temp_name at $disk_max_temp_value°C"
fi

# Calculate new fan speed
# Handle cases where no disks are found
if [[ ${#disk_list[@]} -gt 0 && ${#disk_list[@]} -ne ${#disk_temp[@]} ]]
then
    fan_msg="No disks included or unable to read all disks"
    fan_pwm=$MAX_PWM

# Parity is running
elif [[ "$disk_parity" -gt 0 ]]
then
    fan_msg="Parity-Check is running"
    fan_pwm=$MAX_PWM

# All disk are spun down
elif [[ $disk_active_num -eq 0 ]]
then
    fan_msg="All disks are in standby mode"
        fan_pwm=$MIN_PWM

# Hottest disk is below the LOW_TEMP threshold
elif (( $disk_max_temp_value <= $LOW_TEMP ))
then
        fan_msg="Temperature of $disk_max_temp_value°C is below LOW_TEMP ($LOW_TEMP°C)"
        fan_pwm=$MIN_PWM

# Hottest disk is between LOW_TEMP and HIGH_TEMP
elif (( $disk_max_temp_value > $LOW_TEMP && $disk_max_temp_value <= $HIGH_TEMP ))
then
    fan_msg="Temperature of $disk_max_temp_value°C is between LOW_TEMP ($LOW_TEMP°C) and HIGH_TEMP ($HIGH_TEMP°C)"
        fan_pwm=$(( ((disk_max_temp_value - LOW_TEMP - 1) * pwm_increment) + MIN_PWM ))

# Hottest disk is between HIGH_TEMP and MAX_TEMP
elif (( $disk_max_temp_value > $HIGH_TEMP && $disk_max_temp_value <= $MAX_TEMP ))
then
    fan_msg="Temperature of $disk_max_temp_value°C is between HIGH_TEMP ($HIGH_TEMP°C) and MAX_TEMP ($MAX_TEMP°C)"
        fan_pwm=$MAX_PWM

# Hottest disk exceeds MAX_TEMP
elif (( $disk_max_temp_value > $MAX_TEMP ))
then
    alert_msg="$disk_max_temp_name exceeds ($MAX_TEMP°C)"
    fan_msg=$alert_msg
    fan_pwm=$MAX_PWM

    # Send an alert
    /usr/local/emhttp/webGui/scripts/notify \
        -i alert \
        -s "Disk (${disk_max_temp_name}) overheated" \
        -d "$alert_msg"

# Handle any unexpected condition
else
    fan_msg="An unexpected condition occurred"
    fan_pwm=$MAX_PWM
fi

# Apply fan speed
for fan in "${ARRAY_FANS[@]}"
do
    # Set fan mode to 1 if necessary
    pwm_mode=$(cat "${fan}_enable")
    if [[ $pwm_mode -ne 1 ]]; then
        echo 1 > "${fan}_enable"
    fi

    # Set fan speed
    echo $fan_pwm > $fan
done

pwm_percent=$(( (fan_pwm * 100) / 255 ))
echo "$fan_msg, setting fans to $fan_pwm PWM ($pwm_percent%)"

Al igual que el anterior script este también es configurable, eligiendo la temperatura mas baja a la cual el ventilador deja de giar, revoluciones miniamos, máximas, etc

También nos va a permitir seleccionar los discos a incluir o excluir a monitorizar. Un script bastante configurable como puedes ver.

Comprueba que el script se ejecuta sin errores

Por ultimo configuralo para que se ejecute cada 5 minutos, por ejemplo:

Espero que te haya gustado, pasa un gran día 🐧

Referencia:


Ingrese la dirección de su instancia