Controle de Temperatura - Acer Predator Neo 16 - PHN16-72 - Pode ser adaptado a outros sistemas

Compartilho uma solução para um problema que me afetava em um Laptop Acer Predator Helios Neo 16 - PHN16-72. Mas que pode com alguns poucos ajustes ajudar outras pessoas com o mesmo problema.

O Problema:

O acer não tem na sua BIOS o controle de temperatura que possa ser alterado fica tudo escondido e pode ser modificado (via Windows) com o app da própria Acer. No linux por algum motivo esse controle era inexistente ou ineficiente e o micro passou a desligar-se por problema de super aquecimento. Por tratar-se de um core i7 com uma 4070 isso ficou perigosamente frequente.

Depois de muito pesquisar, com um pouco de ajuda do ChatGPT (e me atrapalhou bastante também) cheguei a uma solução que pode ajudar mais pessoas e deixo aqui o registro. Foi feito baseado no CachyOS (Arch) meu sistema atual, mas com poucos ajustes pode ser usado em outras distribuições.

:ice: GUIA COMPLETO — CONTROLE DE FAN (ACER PREDATOR + LINUX)

:bullseye: Objetivo

Restaurar controle de fan em notebooks Acer Predator no Linux, especialmente após kernels novos onde NBFC quebra ou fica instável.


:warning: Pré-requisitos

  • Linux (Arch / CachyOS / derivados testados)

  • GPU NVIDIA (testado com RTX 30/40)

  • Acesso root (sudo)

  • NBFC instalado


:package: 1. Instalar dependências

:wrench: Pacotes necessários

Arch / CachyOS:

sudo pacman -S lm_sensors nvidia-utils stress-ng

NBFC (AUR):

yay -S nbfc-linux

:magnifying_glass_tilted_left: Detectar sensores

sudo sensors-detect

Aceita tudo com YES.

Depois testa:

sensors

:gear: 2. Preparar acesso ao EC

:fire: Habilitar escrita no EC

sudo modprobe ec_sys write_support=1

Persistir:

echo "options ec_sys write_support=1" | sudo tee /etc/modprobe.d/ec_sys.conf

:brain: 3. Configurar NBFC

Edita:

sudo nano /etc/nbfc/nbfc.json

Conteúdo:

{
   "SelectedConfigId": "Acer Predator PH315-54",
   "EmbeddedControllerType": "dev_port"
}

:rocket: Teste básico

sudo nbfc start
nbfc status

Se aparecer ativo → OK.


:scroll: 4. Criar script de controle

Cria o arquivo:

mkdir -p ~/bin
nano ~/bin/fan-control.sh

:rocket: Script

#!/bin/bash

LOGDIR="/tmp/fan-control"
mkdir -p "$LOGDIR"

temps=()

last_speed=-1
last_change_time=0
last_cpu_temp=0

start_nbfc() {
    if ! nbfc status >/dev/null 2>&1; then
        nbfc stop >/dev/null 2>&1
        sleep 1
        nbfc start
        sleep 2
    fi
}

get_cpu_temp() {
    sensors | grep "Package id 0" | awk '{print int($4)}' | tr -d '+°C'
}

get_nvidia_temp() {
    nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader,nounits 2>/dev/null
}

get_gpu_usage() {
    nvidia-smi --query-gpu=utilization.gpu --format=csv,noheader,nounits 2>/dev/null
}

get_cpu_usage() {
    top -bn1 | grep "Cpu(s)" | awk '{print int(100 - $8)}'
}

is_on_ac() {
    grep -q 1 /sys/class/power_supply/AC*/online 2>/dev/null
}

get_avg_temp() {
    local sum=0
    [ "${#temps[@]}" -eq 0 ] && echo 0 && return

    for t in "${temps[@]}"; do
        sum=$((sum + t))
    done
    echo $((sum / ${#temps[@]}))
}

start_nbfc

while true; do
    LOGFILE="$LOGDIR/fan-control-$(date +%Y-%m-%d).log"

    cpu_temp=$(get_cpu_temp)
    nvidia_temp=$(get_nvidia_temp)
    cpu_usage=$(get_cpu_usage)
    gpu_usage=$(get_gpu_usage)

    [ -z "$cpu_temp" ] && cpu_temp=0
    [ -z "$nvidia_temp" ] && nvidia_temp=0
    [ -z "$cpu_usage" ] && cpu_usage=0
    [ -z "$gpu_usage" ] && gpu_usage=0

    # média móvel (mantida pra log/diagnóstico)
    temps+=($cpu_temp)
    if [ "${#temps[@]}" -gt 5 ]; then
        temps=("${temps[@]:1}")
    fi

    avg_temp=$(get_avg_temp)
    current_time=$(date +%s)

    ############################################
    # 🧠 DETECÇÃO DE CARGA GLOBAL
    ############################################
    if [ "$cpu_usage" -gt 70 ] || [ "$gpu_usage" -gt 70 ]; then
        load_mode="heavy"
    elif [ "$cpu_usage" -gt 30 ] || [ "$gpu_usage" -gt 30 ]; then
        load_mode="medium"
    else
        load_mode="light"
    fi

    ############################################
    # ⚡ PERFIL (AC vs bateria)
    ############################################
    if is_on_ac; then
        profile="performance"
    else
        profile="silent"
    fi

    ############################################
    # 🔥 TEMPERATURA DOMINANTE
    ############################################
    max_temp=$cpu_temp
    [ "$nvidia_temp" -gt "$max_temp" ] && max_temp=$nvidia_temp

    ############################################
    # 🎯 CURVA INTELIGENTE
    ############################################
    if [ "$profile" = "performance" ]; then

        case $load_mode in
            heavy)
                if [ "$max_temp" -ge 80 ]; then speed=100
                elif [ "$max_temp" -ge 70 ]; then speed=90
                elif [ "$max_temp" -ge 60 ]; then speed=80
                else speed=70
                fi
                ;;
            medium)
                if [ "$max_temp" -ge 75 ]; then speed=90
                elif [ "$max_temp" -ge 65 ]; then speed=75
                elif [ "$max_temp" -ge 55 ]; then speed=60
                else speed=50
                fi
                ;;
            light)
                if [ "$max_temp" -ge 70 ]; then speed=80
                elif [ "$max_temp" -ge 60 ]; then speed=60
                else speed=40
                fi
                ;;
        esac

    else
        if [ "$max_temp" -ge 80 ]; then speed=90
        elif [ "$max_temp" -ge 70 ]; then speed=70
        elif [ "$max_temp" -ge 60 ]; then speed=50
        else speed=30
        fi
    fi

    ############################################
    # 🔥 SEGURANÇA ABSOLUTA
    ############################################
    if [ "$cpu_temp" -ge 90 ] || [ "$nvidia_temp" -ge 88 ]; then
        speed=100
    fi

    ############################################
    # 🔄 HISTERese
    ############################################
    if [ "$speed" -gt "$last_speed" ]; then
        apply=1
        last_change_time=$current_time

    elif [ "$speed" -lt "$last_speed" ]; then
        if [ "$cpu_temp" -le $((last_cpu_temp - 3)) ] && \
           [ $((current_time - last_change_time)) -gt 8 ]; then
            apply=1
            last_change_time=$current_time
        else
            apply=0
        fi
    else
        apply=0
    fi

    ############################################
    # 🔧 NBFC CHECK
    ############################################
    if ! nbfc status >/dev/null 2>&1; then
        echo "$(date '+%F %T') | NBFC caiu, reiniciando..." >> "$LOGFILE"
        start_nbfc
    fi

    ############################################
    # 🚀 APPLY (SEM FLOOD)
    ############################################
    if [ "$apply" -eq 1 ]; then
        nbfc set -s "$speed"
        last_speed=$speed
    fi

    ############################################
    # 🔔 ALERTA
    ############################################
    if [ "$cpu_temp" -ge 85 ]; then
        notify-send "🔥 CPU CRÍTICA: ${cpu_temp}°C"
    fi

    ############################################
    # 📝 LOG
    ############################################
    echo "$(date '+%F %T') | CPU:${cpu_temp}°C GPU:${nvidia_temp}°C CPU_LOAD:${cpu_usage}% GPU_LOAD:${gpu_usage}% MODE:${profile}/${load_mode} FAN:${speed}%" >> "$LOGFILE"

    find "$LOGDIR" -name "fan-control-*.log" -mtime +7 -delete

    last_cpu_temp=$cpu_temp

    sleep 5
done

:locked_with_key: Permissão

chmod +x ~/bin/fan-control.sh

:gear: 5. Criar serviço systemd

Cria:

sudo nano /etc/systemd/system/fan-control.service

Conteúdo:

[Unit]
Description=Fan Control Script
After=multi-user.target

[Service]
ExecStart=/home/SEU_USUARIO/bin/fan-control.sh
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

:backhand_index_pointing_right: Substitui SEU_USUARIO


:counterclockwise_arrows_button: Ativar serviço

sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable fan-control
sudo systemctl start fan-control

:bar_chart: Ver status

sudo systemctl status fan-control

:test_tube: 6. Testar funcionamento

:fire: Monitorar log

tail -f /tmp/fan-control/fan-control-$(date +%Y-%m-%d).log

:bomb: Teste de carga

stress-ng --cpu 8

:white_check_mark: Comportamento esperado

  • Fan sobe antes do spike térmico

  • CPU/GPU não passam de ~80–85°C facilmente

  • Sem “respiração” (oscilação constante)

:brain: Como funciona (resumo técnico)

O script:

  • lê:

    • temperatura CPU

    • temperatura GPU

    • uso CPU (%)

    • uso GPU (%)

  • decide baseado em:

    • carga (leve / média / pesada)

    • fonte de energia (AC vs bateria)

    • temperatura dominante

  • aplica:

    • curva dinâmica

    • histerese (evita oscilar)

    • proteção térmica

2 curtidas