I have created script + systemd for my Rock 5B+ with Radxa Heatsink 6240B, maybe someone finds it usefull
- Fan controler
sudo tee /usr/local/bin/rock5bplus-fan.sh >/dev/null <<‘EOF’
#!/usr/bin/env bash
# ROCK 5B+ fan control: 0 (off), 40 (quiet), 255 (full) with hysteresis.
# Because on this board with this fan 100…255 all sound like a hair dryer anyway.
set -euo pipefail
# Find the pwmfan hwmon
find_pwmfan() {
for d in /sys/class/hwmon/hwmon*; do
[[ -r “$d/name” ]] || continue
if [[ “$(cat “$d/name”)” == “pwmfan” ]]; then
echo “$d”
return 0
fi
done
echo “pwmfan hwmon not found” >&2
exit 1
}
HWMON="$(find_pwmfan)"
PWM="$HWMON/pwm1"
MODE="$HWMON/pwm1_enable"
# Manual mode (1)
echo 1 > “$MODE” || true
# Read temp (°C) from all useful sensors; return the max.
read_maxtemp() {
local max=-273 cur d n f
for d in /sys/class/hwmon/hwmon*; do
f="$d/name"
n="$(cat “$f” 2>/dev/null || true)"
case “$n” in
soc_thermal|bigcore0_thermal|bigcore1_thermal|littlecore_thermal|center_thermal|gpu_thermal|npu_thermal)
cur=$(awk ‘{printf “%.0f”, $1/1000}’ “$d/temp1_input” 2>/dev/null || echo 0)
(( cur > max )) && max="$cur"
;;
esac
done
echo “${max:-0}”
}
# Fan levels
OFF=0 # off
QUIET=40 # your board: “very quiet”
FULL=255 # sounds like max from 100…255, so skip the pretense
# Hysteresis thresholds (°C)
# Raise: quiet→full at >= 70; off→quiet at >= 50
# Lower: full→quiet at <= 64; quiet→off at <= 45
HI_FULL=70; LO_FULL=64
HI_QUIET=50; LO_QUIET=45
# Start conservative
current=$OFF
echo “$current” > “$PWM”
while true; do
t=$(read_maxtemp)
case $current in
$OFF)
if (( t >= HI_QUIET )); then current=$QUIET; fi
;;
$QUIET)
if (( t >= HI_FULL )); then current=$FULL
elif (( t <= LO_QUIET )); then current=$OFF
fi
;;
$FULL)
if (( t <= LO_FULL )); then current=$QUIET; fi
;;
esac
echo “$current” > “$PWM” 2>/dev/null || true
printf “T=%s°C pwm=%s mode=%s\n” “$t” “$(cat “$PWM”)” “$(cat “$MODE”)” 1>&2
sleep 2
done
EOF
sudo chmod +x /usr/local/bin/rock5bplus-fan.sh
-
This is systemd entry
sudo tee /etc/systemd/system/rock5bplus-fan.service >/dev/null <<'EOF' [Unit] Description=ROCK 5B+ fan curve (pwm-fan) After=multi-user.target StartLimitIntervalSec=0
[Service] Type=simple ExecStart=/usr/local/bin/rock5bplus-fan.sh Restart=always RestartSec=2
[Install] WantedBy=multi-user.target EOF
sudo systemctl daemon-reload
sudo systemctl enable --now rock5bplus-fan.service
systemctl status rock5bplus-fan.service --no-pager
-
One-liner watcher to monitor temps and PWM in real time
watch -n1 ' for d in /sys/class/hwmon/hwmon*; do n=$(cat "$d/name" 2>/dev/null || true) case "$n" in soc_thermal|bigcore0_thermal|bigcore1_thermal|littlecore_thermal|center_thermal|gpu_thermal|npu_thermal) t=$(awk "{printf \"%.0f\", \$1/1000}" "$d/temp1_input" 2>/dev/null); printf "%-18s %3s°C\n" "$n" "$t" ;; pwmfan) printf "%-18s pwm=%s mode=%s\n" "pwmfan" "$(cat "$d/pwm1")" "$(cat "$d/pwm1_enable")" ;; esac done'
The Radxa 6240B heatsink fan header is two-wire (power + ground, with PWM modulation) . There’s no tachometer line (the third yellow wire you’d normally see on a PC fan), so the driver cannot measure actual RPM so watcher script line will always return rpm=n/a.