Skip to content

Auto Fan Boost #9

@ghost

Description

With help of AI I created a script to control fan boost based on cpu/gpu temperatures:

#!/usr/bin/env bash

CONFIG="auto_fan.conf"
CHECK_INTERVAL=5

declare -a CPU_RULES GPU_RULES
LAST_CPU_BOOST=""
LAST_GPU_BOOST=""

HYSTERESIS=3

LAST_CPU_TEMP=""
LAST_GPU_TEMP=""

# Load config
load_config() {
	local section=""
	while IFS= read -r line; do
		line=$(echo "$line" | sed 's/[[:space:]]//g')
		[[ -z "$line" || "$line" =~ ^# ]] && continue

		if [[ "$line" =~ ^\[(.*)\]$ ]]; then
			section="${BASH_REMATCH[1]}"
			continue
		fi

		if [[ "$line" =~ ^([0-9]+)-([0-9]+)=([0-9]+)$ ]]; then
			rule="${BASH_REMATCH[1]}-${BASH_REMATCH[2]}=${BASH_REMATCH[3]}"
			if [[ "$section" == "CPU" ]]; then
				CPU_RULES+=("$rule")
			elif [[ "$section" == "GPU" ]]; then
				GPU_RULES+=("$rule")
			fi
		fi
	done < "$CONFIG"
}

# Match temperature to a rule
match_boost() {
	local TEMP=$1
	local -n RULES=$2

	for rule in "${RULES[@]}"; do
		IFS='-=' read -r MIN MAX BOOST <<< "$rule"
		if (( TEMP >= MIN && TEMP <= MAX )); then
			echo "$BOOST"
			return
		fi
	done
	echo ""
}

check_g_mode() {
	awcc qm 2>/dev/null | grep -iq 'G-Mode'
}

get_temp_cpu() {
	sensors dell_ddv-virtual-0 | grep 'CPU:' | sed 's/\s\+/ /g' | cut -f 2 -d ' ' | tr -d '+' | sed 's/\..*//'
}

get_temp_gpu() {
	sensors dell_ddv-virtual-0 | grep 'Video:' | sed 's/\s\+/ /g' | cut -f 2 -d ' ' | tr -d '+' | sed 's/\..*//'
}

load_config

CLEANED=''

# Cleanup function to reset fan boost
cleanup() {
	[[ -z "$CLEANED" ]] || return
	CLEANED="YES"

	if ! check_g_mode; then
		echo "Exiting: resetting fan boosts to 0"
		awcc scb 0
		awcc sgb 0
	else
		echo "Exiting in G-Mode: leaving boosts unchanged"
	fi
	exit 0
}

# Trap script termination signals
trap cleanup SIGINT SIGTERM EXIT

while true; do
	if check_g_mode; then
		LAST_CPU_BOOST=""
		LAST_GPU_BOOST=""
		sleep "$CHECK_INTERVAL"
		continue
	fi

	CPU_TEMP=$(get_temp_cpu)
	GPU_TEMP=$(get_temp_gpu)

	[[ -z "$CPU_TEMP" || -z "$GPU_TEMP" ]] && sleep "$CHECK_INTERVAL" && continue

	CPU_BOOST=$(match_boost "$CPU_TEMP" CPU_RULES)
	GPU_BOOST=$(match_boost "$GPU_TEMP" GPU_RULES)

	if [[ -n "$CPU_BOOST" && "$CPU_BOOST" != "$LAST_CPU_BOOST" ]]; then
		if [[ -z "$LAST_CPU_TEMP" || $(( CPU_TEMP > LAST_CPU_TEMP + HYSTERESIS || CPU_TEMP < LAST_CPU_TEMP - HYSTERESIS )) -ne 0 ]]; then
			echo cpu "$CPU_TEMP $CPU_BOOST"
			awcc scb "$CPU_BOOST"
			LAST_CPU_BOOST="$CPU_BOOST"
			LAST_CPU_TEMP="$CPU_TEMP"
		fi
	fi

	if [[ -n "$GPU_BOOST" && "$GPU_BOOST" != "$LAST_GPU_BOOST" ]]; then
		if [[ -z "$LAST_GPU_TEMP" || $(( GPU_TEMP > LAST_GPU_TEMP + HYSTERESIS || GPU_TEMP < LAST_GPU_TEMP - HYSTERESIS )) -ne 0 ]]; then
			echo gpu "$GPU_TEMP $GPU_BOOST"
			awcc sgb "$GPU_BOOST"
			LAST_GPU_BOOST="$GPU_BOOST"
			LAST_GPU_TEMP="$GPU_TEMP"
		fi
	fi

	sleep "$CHECK_INTERVAL"
done

auto_fan.conf:

[CPU]
0-39=0
40-49=20
50-59=40
60-69=60
70-79=80
80-100=100

[GPU]
0-39=0
40-49=20
50-59=40
60-69=60
70-79=80
80-100=100

I don't make a pull request because I want to write it in C, but have no enough time right now.
Just wanted to share this script, and maybe someone will have a time to rewrite in C or review the code 🙂.
Would be nice to have a systemd unit with fan management.
The ChatGPT conversation: https://chatgpt.com/share/6851194a-5000-8013-bfb7-a78ea86cdc30

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions