Show by Label

Tuesday, May 28, 2019

_HowTo: CPU temperature driven fan

This topic was one of my earliest postings on the raspberry Pi Forum (December 2013).

This is a PWM driven fan based on the core temperature. It was originally designed for my MediaCenter that ran on my overclocked RPi Model B (the very first model)

I recently needed something like this for my RPi Model 3 B+, so I looked it up again.

Here is the original post : https://www.raspberrypi.org/forums/viewtopic.php?f=35&t=62438&p=463458

Even after all the changes with Raspbian, 6 years later it still works.

The code posted in the forum works, but there is a more clever way to get the temperature reading without having to put it in a file, and then read it out again for processing. I now also use Python 3.5.

I'm using a small 5V fan. I like the Noctua NF-A4x10 5V, it is very quiet does not consume a lot of power and I'm using it for all my RPi Model 3's.

If you like what you see, please support me by buying me a coffee: https://www.buymeacoffee.com/M9ouLVXBdw
 

Here is the latest version that I'm using at the moment:


#!/usr/bin/python3
#-------------------------------------------------------------------------------
# Name:        run_fan.py
# Purpose:     use PWM to run a fan to keep the core temperature in check
#
# Author:      Paul Versteeg
#
# Created:     01-12-2013, modified june 2019
# Copyright:   (c) Paul 2013, 2019
# Licence:     <your licence>
#-------------------------------------------------------------------------------

import RPi.GPIO as GPIO
from time import sleep
import subprocess
import shlex
import string
import sys, os
import traceback

DEBUG = True

FAN_PIN = 4 # GPIO 4

GPIO.setwarnings(False) # when everything is working you could turn warnings off
GPIO.setmode(GPIO.BCM)  # choose BCM numbering scheme.
GPIO.setup(FAN_PIN, GPIO.OUT)# set GPIO port as output driver for the Fan


Fan = GPIO.PWM(FAN_PIN, 100) # create object Fan for PWM on port 22 at 100 Hertz
Fan.start(0)            # start Fan on 0 percent duty cycle (off)

delay = 30              # seconds of delay, testing the core every 30 seconds is OK
cool_baseline = 60      # start cooling from this temp in Celcius onwards
pwm_baseline = 40       # lowest PWM to keep the fan running
factor = 3              # multiplication factor
max_pwm = 100           # maximum PWM value
fan_running = False     # helps to kick-start the fan

def main():
    global fan_running
    '''
    This program controls a Fan by using PWM.
    The Fan will probably not work below 40% dutycycle, so that is the
    fan PWM baseline. The maximum PWM cannot be more than 100%.

    When the cpu temperature is above 50 'C, we will start to cool.
    When the cpu reaches 70 degrees, we would like to run the fan at max speed.

    To make the PWM related to the temperature, strip the actual temp from the
    cool baseline, multiply the delta with 3 and add that to the the baseline
    PWM to get 100% at 70 degrees.

    I have selected a PWM frequency of 100Hz to avoid high frequency noise, but
    you can change that.
    '''
    try:
        while True:
                # get the core temperature
                # need to use the full path otherwise root cannot find it
                cmd = "/opt/vc/bin/vcgencmd measure_temp"
                args = shlex.split(cmd)
                output, error = subprocess.Popen(args, stdout = subprocess.PIPE, \
                                stderr= subprocess.PIPE).communicate()

                # strip the temperature out of the returned string
                # the returned string is in the form : b"temp=43.9'C\n"
                # if your localization is set to US, you get the temp in Fahrenheit,
                # so you need to adapt the stripping somewhat
                #
                core_temp = float(output[5:9]) # for Celcius

                if DEBUG : print (core_temp)

                if core_temp < cool_baseline :
                    Fan.ChangeDutyCycle(0) # turn Fan off
                    fan_running = False

                if core_temp > cool_baseline :
                    if fan_running :
                        duty_cycle = ((core_temp - cool_baseline)*factor)+pwm_baseline
                        if duty_cycle > max_pwm : duty_cycle = max_pwm # max = 100%
                    else:
                        # kick-start the fan for one cycle
                        duty_cycle = 70
                        fan_running = True

                    Fan.ChangeDutyCycle(duty_cycle)   # output the pwm

                    if DEBUG : ("pwm {:.2f}".format(duty_cycle))

                sleep(delay)

    # the following will allow you to kill the program
    except KeyboardInterrupt:
        Fan.stop()      # stop the PWM output
        GPIO.cleanup()  # clean up GPIO on CTRL+C exit()

    except Exception as e:
        sys.stderr.write("Got exception: %s" % e)
        if DEBUG :
            print(traceback.format_exc())
            print("GPIO.cleanup")
        GPIO.output(FAN_PIN, GPIO.LOW)
        GPIO.cleanup(
FAN_PIN) # leave the other pins alone
        os._exit(1)


if __name__ == '__main__':
    main()




Enjoy!