For a couple of years, the Raspberry Pi I was running OSMC on was housed in an old settop box I bought at a secondhand shop in my town. There was no power brick with it, which dropped the price a lot. There was no airflow at all, which resulted in a system that got a bit warm. So started looking for a better case, but never found an appealing replacement that also had a FAF (Family Approval Factor). Until a couple of months ago while browsing Thingiverse.com for 3 Printable cases and among the standard boxes there was a case based on the Mac Pro I liked the looks of it. And do have a 3d printer, so why not. I started printing and after a couple of long prints talking some 24+ hours of printing I had the parts ready.
Cooler but not much
The first tests did show a lower base temperature was lower, but playing a movie still resulted in a temperature warning, so more work was needed. Since the case has room for a fan at the top to pull air though the case, I went on a fan hunt. At first the plan was to buy a simple 12v fan and power it From the same 5v power supply that powers the Pi, but knowing that not all 12v fans can start at 5v I added ‘5v’ to my search string. That way I came across a 5v 80 mm fan from Noctua that also was PWM-enabled. Noctua is known for making silent fans, and being PWM-enabled gave me an idea would it be possible to create the PWM signal with the Pi itself and control the speed based on the temperature. In my search I came stumbled on this blog post which was what I needed. So order placed and the script downloaded. I knew I had to look for another PWM pin the pin 18 was occupied by my IR receiver looking at the pinout I saw that pin 19 which was free to use was also an PWM output.
import RPi.GPIO as GPIO
import time
import signal
import sys
import os
# Configuration
FAN_PIN = 18 # BCM pin used to drive PWM fan
WAIT_TIME = 1 # [s] Time to wait between each refresh
PWM_FREQ = 25000 # [Hz] 25kHz for Noctua PWM control
# Configurable temperature and fan speed
MIN_TEMP = 40
MAX_TEMP = 70
FAN_LOW = 40
FAN_HIGH = 100
FAN_OFF = 0
FAN_MAX = 100
# Get CPU's temperature
def getCpuTemperature():
res = os.popen('vcgencmd measure_temp').readline()
temp =(res.replace("temp=","").replace("'C\n",""))
#print("temp is {0}".format(temp)) # Uncomment for testing
return temp
# Set fan speed
def setFanSpeed(speed):
fan.start(speed)
return()
# Handle fan speed
def handleFanSpeed():
temp = float(getCpuTemperature())
# Turn off the fan if temperature is below MIN_TEMP
if temp < MIN_TEMP:
setFanSpeed(FAN_OFF)
#print("Fan OFF") # Uncomment for testing
# Set fan speed to MAXIMUM if the temperature is above MAX_TEMP
elif temp > MAX_TEMP:
setFanSpeed(FAN_MAX)
#print("Fan MAX") # Uncomment for testing
# Caculate dynamic fan speed
else:
step = (FAN_HIGH - FAN_LOW)/(MAX_TEMP - MIN_TEMP)
temp -= MIN_TEMP
setFanSpeed(FAN_LOW + ( round(temp) * step ))
#print(FAN_LOW + ( round(temp) * step )) # Uncomment for testing
return ()
try:
# Setup GPIO pin
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(FAN_PIN, GPIO.OUT, initial=GPIO.LOW)
fan = GPIO.PWM(FAN_PIN,PWM_FREQ)
setFanSpeed(FAN_OFF)
# Handle fan speed every WAIT_TIME sec
while True:
handleFanSpeed()
time.sleep(WAIT_TIME)
except KeyboardInterrupt: # trap a CTRL+C keyboard interrupt
setFanSpeed(FAN_HIGH)
#GPIO.cleanup() # resets all GPIO ports used by this function
To start the script after a restart whithout the need for manual intervention I created a file fan_control.service in /lib/systemd/system/
whit the following contents:
[Unit]
Description=Fan control
After=multi-user.target
Conflicts=getty@tty1.service
[Service]
Type=idle
ExecStart= /usr/bin/python /home/osmc/Scripts/fan_control.py
[Install]
WantedBy=multi-user.target
Then I had to issue the command sudo systemctl enable fan_control.service
to start the script at boot. Now whenever the Raspberry is powered down the fan spins at 100% and is audible, as soon as the script kicks in the sound levels go down to a slight hum which you can just about notice in a silent room. There is a good airflow out the top of the case and the temperatures stay below 70 °C.