Skip to content

CPU/GPU overheating notifications

A dust-clogged heatsink, a stalled fan, a heavy render in summer — and the CPU is already throttling while the whole machine starts to lag. It’s easier to find out from a push right away than to guess why everything slowed down.

Install lm-sensors and read the temperature machine-readably via sensors -u. Run sudo sensors-detect once so the sensors are picked up.

Script ~/bin/notifly-cpu-temp:

#!/usr/bin/env bash
set -eu
set -a; source ~/.notifly.env; set +a
WARN=80 # °C — warning
CRIT=90 # °C — critical
STATE_FILE=/tmp/notifly-cputemp.state
PREV=$(cat "$STATE_FILE" 2>/dev/null || echo OK)
# Highest temperature across all cores (lines like "tempN_input: 74.000").
CPU=$(sensors -u | awk '/_input:/ {print $2}' | sort -nr | head -1)
CPU=${CPU%.*}
# NVIDIA GPU temperature (if nvidia-smi is present).
GPU=""
if command -v nvidia-smi >/dev/null; then
GPU=$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader,nounits | sort -nr | head -1)
fi
# Take the max of CPU and GPU to decide the level.
MAX=$CPU
[[ -n "$GPU" && "$GPU" -gt "$MAX" ]] && MAX=$GPU
if (( MAX >= CRIT )); then NOW=CRIT
elif (( MAX >= WARN )); then NOW=WARN
else NOW=OK
fi
send() { ~/bin/notifly-send "$1" "$2" "$3"; }
BODY="CPU: ${CPU}°C${GPU:+, GPU: ${GPUC}"
# Only send on level change, so we don't spam every minute.
if [[ "$NOW" != "$PREV" ]]; then
case "$NOW" in
CRIT) send "🔥 Перегрев ${MAX}°C" "$BODY — проверьте охлаждение!" 9 ;;
WARN) send "🌡 Нагрев ${MAX}°C" "$BODY" 6 ;;
OK) [[ "$PREV" != OK ]] && send "✅ Температура в норме" "$BODY" 3 ;;
esac
fi
echo "$NOW" > "$STATE_FILE"

Make it executable and set up a systemd timer to run every 30 seconds:

~/.config/systemd/user/notifly-cpu-temp.service
[Unit]
Description=Notifly CPU/GPU temperature check
[Service]
Type=oneshot
ExecStart=%h/bin/notifly-cpu-temp
~/.config/systemd/user/notifly-cpu-temp.timer
[Unit]
Description=Run notifly-cpu-temp every 30s
[Timer]
OnBootSec=2min
OnUnitActiveSec=30s
[Install]
WantedBy=timers.target
Окно терминала
systemctl --user daemon-reload
systemctl --user enable --now notifly-cpu-temp.timer

macOS has no lm-sensors. Temperature is read by tools like osx-cpu-temp (brew install osx-cpu-temp) or iStats (gem install iStats):

~/bin/notifly-cpu-temp
#!/usr/bin/env bash
set -eu; set -a; source ~/.notifly.env; set +a
CPU=$(osx-cpu-temp | grep -Eo '[0-9]+' | head -1)
# ... same WARN/CRIT threshold logic as for Linux

Run it through launchd with StartInterval — just like in the battery recipe.

OpenHardwareMonitor (or LibreHardwareMonitor) publishes sensor readings into the root\OpenHardwareMonitor WMI namespace. Run it in the background, then use PowerShell. Assumes a configured function Send-Notifly.

C:\scripts\Notifly-CpuTemp.ps1
. $env:USERPROFILE\Documents\WindowsPowerShell\Notifly.ps1
$Warn = 80
$Crit = 90
$State = "$env:LOCALAPPDATA\notifly-cputemp.state"
$prev = if (Test-Path $State) { (Get-Content $State -Raw).Trim() } else { "OK" }
# All temperature sensors from OpenHardwareMonitor.
$temps = Get-CimInstance -Namespace "root\OpenHardwareMonitor" -ClassName Sensor `
-ErrorAction SilentlyContinue | Where-Object { $_.SensorType -eq "Temperature" }
$max = ($temps | Measure-Object -Property Value -Maximum).Maximum
$max = [int]$max
$now = if ($max -ge $Crit) { "CRIT" }
elseif ($max -ge $Warn) { "WARN" }
else { "OK" }
if ($now -ne $prev) {
switch ($now) {
"CRIT" { Send-Notifly -Title "🔥 Перегрев $max°C" -Message "Проверьте охлаждение!" -Priority 9 }
"WARN" { Send-Notifly -Title "🌡 Нагрев $max°C" -Message "" -Priority 6 }
"OK" { if ($prev -ne "OK") { Send-Notifly -Title "✅ Температура в норме" -Message "$max°C" -Priority 3 } }
}
}
$now | Set-Content $State

Schedule it every 30 seconds:

Окно терминала
$Action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File C:\scripts\Notifly-CpuTemp.ps1"
$Trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) `
-RepetitionInterval (New-TimeSpan -Seconds 30)
Register-ScheduledTask -TaskName "Notifly CPU Temp" -Action $Action -Trigger $Trigger
  • You learn about overheating before throttling and a sudden reboot.
  • Two levels — 80 °C “keep an eye” and 90 °C “rescue” at priority 9, which gets through even in DND (see priorities).
  • The “temperature is back to normal” push closes the story — the cooler coped.
  • Add fan speed (sensors -u, field fanN_input) — spot a jammed cooler.
  • Include the current load in the message (uptime, nvidia-smi -q -d UTILIZATION).
  • For a home server — keep a watchdog running and send it via monitoring.