O Raspberry Pi 5 possui um sistema de gerenciamento térmico bastante interessante. Além de permitir a leitura da temperatura do processador, o Linux disponibiliza informações sobre o controlador do cooler, PWM, rotação do ventilador, estado térmico e os chamados thermal trip points.
Neste artigo vamos criar um monitor em Python capaz de acompanhar essas informações diretamente através do sistema de arquivos virtual do Linux.
O programa não utiliza bibliotecas externas. Ele acessa diretamente os arquivos disponibilizados pelo kernel em:
/sys/class/thermal
/sys/class/hwmon
/proc/stat
Isso torna o monitor leve e adequado para ser executado continuamente em um Raspberry Pi 5.

1. O que o programa monitora
O monitor apresenta várias informações importantes:
- temperatura atual da CPU;
- temperatura mínima registrada;
- temperatura máxima registrada;
- utilização da CPU;
- controlador do cooler;
- valor PWM aplicado ao cooler;
- rotação do cooler em RPM;
- modo automático ou manual do PWM;
- estado atual do sistema de refrigeração;
- estado máximo do sistema de refrigeração;
- tipo do dispositivo de cooling;
- todos os
thermal trip pointsdisponíveis.
A tela do programa fica aproximadamente assim:
============================================================
Raspberry Pi 5 - MONITOR
============================================================
Hora : 17/09/2026 08:45:32
CPU
------------------------------------------------------------
Temperatura : 47.8 °C
Temp Min : 46.9 °C
Temp Max : 52.3 °C
CPU Load : 8.7 %
COOLER
------------------------------------------------------------
HWMon : /sys/class/hwmon/hwmon2
PWM : 85 / 255
RPM : 1820
Modo : automático
PWM Enable : 1
Thermal : 1 / 4
THERMAL TRIP POINTS
------------------------------------------------------------
Trip 0 : 50.0 °C active
Trip 1 : 60.0 °C active
Trip 2 : 70.0 °C active
Trip 3 : 80.0 °C critical
Cooling device: pwm-fan
============================================================
Figura acima mostra o programa em python rodando, Acesso via RealVNC.Os valores acima são apenas ilustrativos. Os valores reais dependem da configuração do Raspberry Pi, do kernel e da temperatura no momento da leitura.
2. Como o Linux disponibiliza essas informações
Uma das características interessantes do Linux é que muitos dispositivos podem ser monitorados através do filesystem virtual.
No Raspberry Pi 5, a temperatura da CPU pode ser encontrada em:
/sys/class/thermal/thermal_zone0/temp
O valor normalmente é fornecido em milésimos de grau Celsius.
Por exemplo:
47800
corresponde a:
47,8 °C
No programa fazemos essa conversão:
return int(value) / 1000.0
3. Medindo a temperatura
A função responsável pela temperatura é:
def get_temperature():
value = read_file(os.path.join(THERMAL_ZONE, "temp"))
if value is None:
return None
try:
return int(value) / 1000.0
except ValueError:
return None
A vantagem de utilizar /sys/class/thermal é que não precisamos instalar uma biblioteca específica para acessar o sensor.
4. Medindo a utilização da CPU
A utilização do processador é obtida através de:
/proc/stat
O Linux mantém nessa estrutura informações acumuladas sobre o tempo utilizado pela CPU.
O programa lê os campos:
user
nice
system
idle
iowait
irq
softirq
steal
Depois calcula a diferença entre duas leituras consecutivas.
A lógica é:
tempo total
│
├── tempo ocupado
│
└── tempo ocioso
A utilização é calculada por:
usage = 100.0 * (total_delta - idle_delta) / total_delta
Essa abordagem é interessante porque não depende de ferramentas externas como top.
5. Localizando o controlador do cooler
Uma particularidade importante é que não devemos assumir que o cooler estará sempre em:
/sys/class/hwmon/hwmon3
O número do diretório hwmon pode mudar.
Por isso o programa procura automaticamente o dispositivo cujo nome seja:
pwmfan
A função utilizada é:
def find_cooling_fan_hwmon():
base = "/sys/class/hwmon"
if not os.path.exists(base):
return None
for name in sorted(os.listdir(base)):
if not name.startswith("hwmon"):
continue
path = os.path.join(base, name)
device_name = read_file(
os.path.join(path, "name")
)
if device_name == "pwmfan":
return path
return None
Essa abordagem torna o programa mais robusto.
6. PWM do cooler
Depois de localizar o pwmfan, podemos consultar:
pwm1
O programa faz:
pwm = read_file(
os.path.join(hwmon, "pwm1")
)
O valor normalmente está na faixa:
0 ... 255
Portanto, por exemplo:
PWM = 128
representa aproximadamente metade da escala disponível.
É importante observar que PWM não é necessariamente igual a uma porcentagem exata de rotação do ventilador. O comportamento mecânico do fan e o controlador utilizado precisam ser considerados.
7. RPM do cooler
Quando o driver disponibiliza a leitura da rotação, ela pode ser encontrada em:
fan1_input
O programa lê:
rpm = read_file(
os.path.join(hwmon, "fan1_input")
)
Assim podemos obter algo como:
RPM : 1850
Essa informação é particularmente interessante para diagnosticar o cooler.
Por exemplo, podemos observar situações como:
Temperatura sobe
↓
PWM aumenta
↓
RPM aumenta
↓
Temperatura estabiliza
Esse comportamento fornece uma indicação muito mais completa do funcionamento do sistema de refrigeração do que observar somente a temperatura.
8. Modo automático do cooler
Outro parâmetro importante é:
pwm1_enable
O programa interpreta esse valor através da função:
def get_pwm_mode(pwm_enable):
if pwm_enable == 1:
return "automático"
elif pwm_enable == 0:
return "manual"
else:
return "desconhecido"
Assim podemos verificar se o controlador está trabalhando em modo automático ou manual.
Para um sistema que queremos deixar responsável pelo próprio gerenciamento térmico, o modo automático é particularmente importante.
9. Thermal cooling state
Além do PWM, o kernel Linux mantém um estado para o dispositivo de refrigeração:
/sys/class/thermal/cooling_device0/cur_state
O programa lê esse valor com:
def get_thermal_state():
value = read_file(
os.path.join(COOLING_DEVICE, "cur_state")
)
if value is None:
return None
try:
return int(value)
except ValueError:
return None
Também é possível consultar o valor máximo:
/sys/class/thermal/cooling_device0/max_state
Isso permite apresentar:
Thermal : 1 / 4
ou seja, o estado atual em relação ao número máximo de estados disponibilizados pelo dispositivo.
10. Thermal trip points
Uma das partes mais interessantes do programa é a leitura dos thermal trip points.
O kernel pode disponibilizar arquivos como:
trip_point_0_temp
trip_point_0_type
trip_point_1_temp
trip_point_1_type
trip_point_2_temp
trip_point_2_type
e assim por diante.
O programa percorre automaticamente esses arquivos:
def get_trip_points():
trip_points = []
index = 0
while True:
temp_path = os.path.join(
THERMAL_ZONE,
f"trip_point_{index}_temp"
)
type_path = os.path.join(
THERMAL_ZONE,
f"trip_point_{index}_type"
)
temp = read_file(temp_path)
trip_type = read_file(type_path)
if temp is None and trip_type is None:
break
try:
temperature = int(temp) / 1000.0
except (ValueError, TypeError):
temperature = None
trip_points.append({
"index": index,
"temperature": temperature,
"type": trip_type or "unknown",
})
index += 1
return trip_points
Isso evita assumir antecipadamente quantos níveis existem.
11. Por que os trip points são importantes?
Os trip points fazem parte do mecanismo térmico do kernel.
Eles representam temperaturas associadas a diferentes ações térmicas.
Por exemplo, um sistema pode ter pontos associados a estados como:
active
passive
hot
critical
O significado exato e os valores dependem da configuração do sistema e do driver.
Portanto, não devemos simplesmente assumir que determinado valor, como 70 °C, significa obrigatoriamente que o cooler deverá estar em determinada rotação.
O importante é observar o comportamento real do conjunto:
Temperatura
│
▼
Thermal zone
│
▼
Thermal framework
│
▼
Cooling device
│
▼
PWM
│
▼
Fan
│
▼
RPM
12. Atualização a cada dois segundos
O programa utiliza:
INTERVAL = 2
Portanto, a cada dois segundos ele:
- lê a temperatura;
- atualiza mínimo e máximo;
- calcula a utilização da CPU;
- procura os dados do cooler;
- lê o estado térmico;
- lê os trip points;
- atualiza a tela.
No final do ciclo:
time.sleep(INTERVAL)
A tela é limpa antes de cada atualização:
os.system("clear")
Dessa maneira temos um monitor semelhante a uma pequena aplicação de diagnóstico, mas executado diretamente no terminal.
13. Executando o programa
Salve o arquivo, por exemplo:
rpi-monitor.py
Depois dê permissão de execução:
chmod +x rpi-monitor.py
Execute:
./rpi-monitor.py
ou:
python3 rpi-monitor.py
Para encerrar:
Ctrl + C
O programa trata a interrupção através de:
except KeyboardInterrupt:
print()
print("Monitor encerrado.")
14. Uma vantagem importante: nenhuma biblioteca externa
O programa utiliza somente módulos que fazem parte da instalação padrão do Python:
import os
import time
from datetime import datetime
Não é necessário instalar:
pip
numpy
psutil
matplotlib
nem qualquer outra biblioteca.
Isso é uma vantagem para um Raspberry Pi que esteja sendo utilizado como servidor, pois o monitor possui um consumo muito pequeno de recursos.
15. O que podemos diagnosticar com esse monitor?
Esse pequeno programa pode ser utilizado para investigar diversos problemas.
Temperatura elevada
Podemos observar:
CPU Temperature
CPU Load
PWM
RPM
Se a CPU estiver com carga elevada, uma temperatura maior pode ser perfeitamente esperada.
Cooler não acionando
Uma situação interessante seria:
Temperatura : 70 °C
PWM : 0
RPM : 0
Nesse caso existe uma indicação de que precisamos investigar o controlador térmico, o driver ou a conexão do cooler.
Cooler acionando
Outro cenário:
Temperatura : 65 °C
PWM : 120
RPM : 2100
Nesse caso conseguimos observar que o sistema está efetivamente comandando o ventilador.
Cooler aumentando a rotação
O cenário mais interessante para um teste é observar uma sequência como:
50 °C → PWM 60 → 1200 RPM
55 °C → PWM 90 → 1700 RPM
60 °C → PWM 130 → 2200 RPM
65 °C → PWM 170 → 2800 RPM
Os valores acima são apenas um exemplo ilustrativo.
O importante é observar a relação entre temperatura, PWM e RPM no equipamento real.
16. Teste de funcionamento do cooler
Podemos utilizar o monitor juntamente com uma carga artificial da CPU.
Por exemplo, podemos instalar:
sudo apt install stress-ng
e executar:
stress-ng --cpu 4 --timeout 120s
Enquanto isso, em outro terminal:
python3 rpi-monitor.py
Assim podemos acompanhar a evolução da temperatura.
O objetivo não é simplesmente alcançar uma temperatura elevada, mas observar o comportamento do sistema:
Carga CPU
↓
Temperatura aumenta
↓
Controle térmico reage
↓
PWM aumenta
↓
RPM aumenta
↓
Temperatura estabiliza
Esse teste permite verificar de forma prática a interação entre o processador, o kernel e o sistema de refrigeração.
17. Conclusão
O Raspberry Pi 5 oferece ao Linux uma quantidade bastante interessante de informações sobre seu funcionamento interno.
Com poucas linhas de Python é possível acessar diretamente:
/sys/class/thermal
/sys/class/hwmon
/proc/stat
Permite construir uma ferramenta de diagnóstico sem depender de grandes frameworks ou bibliotecas externas.
O ponto mais interessante desse projeto é que não estamos apenas olhando a temperatura da CPU. Estamos acompanhando todo o caminho do gerenciamento térmico:
Esse tipo de monitor é especialmente útil quando o Raspberry Pi 5 está sendo utilizado como servidor, pois permite acompanhar o comportamento térmico sem a necessidade de uma interface gráfica pesada.
No meu caso, essa ferramenta também serve como uma etapa de diagnóstico do Raspberry Pi 5, permitindo verificar não somente a temperatura do processador, mas se o sistema de refrigeração está realmente respondendo ao aumento de temperatura.
O próximo passo natural é transformar esse monitor em uma pequena aplicação gráfica, com gráfico de temperatura, carga da CPU, PWM e RPM ao longo do tempo, permitindo visualizar o comportamento térmico do Raspberry Pi 5 de forma muito mais clara.
Código Fonte Completo
Código-fonte explicado por etapas
Em vez de apresentar o programa completo de uma única vez, vamos analisar suas principais partes. Dessa forma, fica mais fácil entender como o Python obtém as informações térmicas diretamente das interfaces disponibilizadas pelo kernel Linux.
1. Configuração inicial
O programa utiliza somente módulos da biblioteca padrão do Python e define os caminhos das interfaces térmica e de refrigeração do Raspberry Pi 5.
#!/usr/bin/env python3
import os
import time
from datetime import datetime
INTERVAL = 2
THERMAL_ZONE = "/sys/class/thermal/thermal_zone0"
COOLING_DEVICE = "/sys/class/thermal/cooling_device0"O intervalo de atualização é de dois segundos. As informações térmicas são obtidas diretamente através de /sys/class/thermal e /sys/class/hwmon.
2. Função auxiliar para leitura do sistema
def read_file(path, default=None):
try:
with open(path, "r") as file:
return file.read().strip()
except Exception:
return defaultEssa função centraliza a leitura dos arquivos do sistema. Caso um arquivo não exista ou não possa ser lido, o programa retorna None em vez de interromper a execução.
3. Leitura da temperatura da CPU
A temperatura da CPU é disponibilizada pelo kernel através do arquivo /sys/class/thermal/thermal_zone0/temp. O valor normalmente é fornecido em milésimos de grau Celsius.
def get_temperature():
value = read_file(
os.path.join(THERMAL_ZONE, "temp")
)
if value is None:
return None
try:
return int(value) / 1000.0
except ValueError:
return NonePor exemplo, um valor de 47800 corresponde a 47,8 °C.
4. Leitura da utilização da CPU
A utilização do processador é calculada a partir dos contadores disponibilizados pelo Linux em /proc/stat. O programa compara duas leituras consecutivas para determinar a porcentagem de tempo em que a CPU esteve ocupada.
def get_cpu_load():
line = read_file("/proc/stat")
if not line:
return None
values = line.split()
if values[0] != "cpu":
return None
try:
user = int(values[1])
nice = int(values[2])
system = int(values[3])
idle = int(values[4])
iowait = int(values[5])
irq = int(values[6])
softirq = int(values[7])
steal = int(values[8])
except (ValueError, IndexError):
return None
idle_time = idle + iowait
total = (
user
+ nice
+ system
+ idle
+ iowait
+ irq
+ softirq
+ steal
)
return total, idle_timedef cpu_load(previous):
current = get_cpu_load()
if current is None:
return None, previous
if previous is None:
return 0.0, current
total_delta = current[0] - previous[0]
idle_delta = current[1] - previous[1]
if total_delta <= 0:
return 0.0, current
usage = (
100.0 *
(total_delta - idle_delta) /
total_delta
)
return usage, current5. Localizando automaticamente o cooler
O programa não assume que o controlador do cooler estará sempre em um diretório específico como hwmon3. O número do dispositivo pode variar. Por isso, o código procura automaticamente o dispositivo cujo nome seja pwmfan.
def find_cooling_fan_hwmon():
"""
Procura automaticamente o hwmon associado ao cooler.
Não assume que o diretório será hwmon3.
"""
base = "/sys/class/hwmon"
if not os.path.exists(base):
return None
for name in sorted(os.listdir(base)):
if not name.startswith("hwmon"):
continue
path = os.path.join(base, name)
device_name = read_file(
os.path.join(path, "name")
)
if device_name == "pwmfan":
return path
return NoneEssa abordagem torna o monitor mais robusto, pois ele procura o controlador pelo nome informado pelo driver em vez de depender de um número fixo.
6. Leitura do PWM, RPM e estado do cooler
Depois de localizar o controlador, o programa procura as interfaces pwm1, pwm1_enable e fan1_input.
def get_fan_data():
"""
Lê PWM, RPM e modo do cooler.
"""
hwmon = find_cooling_fan_hwmon()
if hwmon is None:
return None
pwm = read_file(os.path.join(hwmon, "pwm1"))
pwm_enable = read_file(
os.path.join(hwmon, "pwm1_enable")
)
rpm = read_file(
os.path.join(hwmon, "fan1_input")
)
try:
pwm = int(pwm) if pwm is not None else None
except ValueError:
pwm = None
try:
pwm_enable = (
int(pwm_enable)
if pwm_enable is not None
else None
)
except ValueError:
pwm_enable = None
try:
rpm = int(rpm) if rpm is not None else None
except ValueError:
rpm = None
return {
"hwmon": hwmon,
"pwm": pwm,
"pwm_enable": pwm_enable,
"rpm": rpm,
}O valor pwm1 representa o valor de PWM disponibilizado pelo driver. Em muitos sistemas ele utiliza uma escala de 0 a 255. Quando disponível, fan1_input fornece a rotação do ventilador em RPM.
O campo pwm1_enable deve ser interpretado de acordo com o driver utilizado. Por isso, o programa mantém o valor bruto em vez de assumir que um determinado valor significa automaticamente “manual” ou “automático”.
7. Estado térmico do cooling device
O framework térmico do Linux também disponibiliza o estado atual e o estado máximo do dispositivo de refrigeração.
def get_thermal_state():
value = read_file(
os.path.join(
COOLING_DEVICE,
"cur_state"
)
)
if value is None:
return None
try:
return int(value)
except ValueError:
return None
def get_thermal_max_state():
value = read_file(
os.path.join(
COOLING_DEVICE,
"max_state"
)
)
if value is None:
return None
try:
return int(value)
except ValueError:
return NoneEsses valores permitem acompanhar a atuação do dispositivo dentro do framework térmico do kernel.
8. Thermal Trip Points
Os thermal trip points são pontos de temperatura disponibilizados pela thermal zone. O programa percorre automaticamente todos os pontos existentes.
def get_trip_points():
"""
Lê todos os trip points disponíveis na thermal_zone0.
"""
trip_points = []
index = 0
while True:
temp_path = os.path.join(
THERMAL_ZONE,
f"trip_point_{index}_temp"
)
type_path = os.path.join(
THERMAL_ZONE,
f"trip_point_{index}_type"
)
temp = read_file(temp_path)
trip_type = read_file(type_path)
if temp is None and trip_type is None:
break
try:
temperature = int(temp) / 1000.0
except (ValueError, TypeError):
temperature = None
trip_points.append({
"index": index,
"temperature": temperature,
"type": trip_type or "unknown",
})
index += 1
return trip_pointsOs arquivos seguem uma estrutura como trip_point_0_temp, trip_point_0_type, trip_point_1_temp, trip_point_1_type e assim por diante.
9. Identificação do cooling device
def get_cooling_device():
device_type = read_file(
os.path.join(
COOLING_DEVICE,
"type"
)
)
return device_typeEssa função consulta o tipo do dispositivo de refrigeração associado ao cooling_device.
10. Loop principal do monitor
A cada ciclo, o programa coleta as informações e atualiza a tela.
while True:
temperature = get_temperature()
load, previous_cpu = cpu_load(previous_cpu)
fan = get_fan_data()
thermal_state = get_thermal_state()
thermal_max_state = get_thermal_max_state()
cooling_type = get_cooling_device()
trip_points = get_trip_points()
clear_screen()
# Exibição dos dados...
time.sleep(INTERVAL)O intervalo definido no início do programa é de dois segundos. O monitor continua executando até que o usuário pressione Ctrl+C.
11. Encerramento do programa
try:
while True:
# monitoramento
time.sleep(INTERVAL)
except KeyboardInterrupt:
print()
print("Monitor encerrado.")O tratamento de KeyboardInterrupt permite encerrar o monitor de forma limpa utilizando Ctrl+C.
Código-fonte completo
Os blocos apresentados acima mostram as principais partes do monitor e explicam como o programa obtém as informações diretamente das interfaces do kernel Linux.
O código-fonte completo está disponível para download no arquivo rpi-monitor.py. O arquivo original deve ser utilizado para execução, preservando integralmente sua indentação e formatação Python.
⬇ Baixar rpi-monitor.py
O arquivo pode ser executado no Raspberry Pi 5 com:
python3 rpi-monitor.pyPróximo passo
Uma evolução natural deste projeto seria transformar o monitor de terminal em uma aplicação capaz de registrar os dados ao longo do tempo e apresentar graficamente a temperatura da CPU, a utilização do processador, o PWM do cooler, a rotação do ventilador e o estado térmico.
Dessa forma, seria possível visualizar graficamente a resposta do sistema de refrigeração à variação da carga do Raspberry Pi 5

Figura acima mostra o programa em python rodando, Acesso via RealVNC.
Deixe um comentário