ChilledPi2 - Advanced fan control for keeping your Raspberry Pi cool

ChilledPi was a useful script, but what if you want to drive each fan differently, maybe even from different temperature readings?


Well now you can make your PicoBorg based cooling system even better with ChilledPi2!

ChilledPi2 can read multiple sensors and control each of the 4 fan drives separately as you desire:


The configuration is a little more complex than before:
  • lSensors, lines 38-40
    This is a list of the sensors you wish to read (they will all be displayed to the user, you can therefore read more then you control from), formatted as follows:
    [name, terminal command to read the sensor, multiplier],
    this allows you to query any sensor you can read from the command line
  • lFans, lines 44-49
    This is a list of which drives to control, stating which sensor they are based on, the temperature to turn on, and the temperature to turn off, formatted as follows:
    [DRIVE_1, 'Processor', 31.0, 33.0],
    this allows you to setup each fan individually, as well as control how many fans re in use (no reference to a drive pin will mean it is ignored by the script).
  • interval, line 52
    The number of seconds between readings, smaller responds quicker but uses more processing power
Our example settings only read the processor temperature, and drive all 4 fans, starting with #1 and then increasing towards all 4 on as the temperature increases.

Here's the code, you can download the ChilledPi2 script file as text here
Save the text file on your pi as ChilledPi2.py
Make the script executable using
chmod +x ChilledP2i.py
and run using
sudo ./ChilledPi2.py

#!/usr/bin/env python
# coding: latin-1

# Import library functions we need
import time
import sys
import os
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

# Set which GPIO pins the drive outputs are connected to
DRIVE_1 = 4
DRIVE_2 = 18
DRIVE_3 = 8
DRIVE_4 = 7

# Set all of the drive pins as output pins
GPIO.setup(DRIVE_1, GPIO.OUT)
GPIO.setup(DRIVE_2, GPIO.OUT)
GPIO.setup(DRIVE_3, GPIO.OUT)
GPIO.setup(DRIVE_4, GPIO.OUT)

# Map the on/off state to nicer names for display
dName = {}
dName[True] = 'ON '
dName[False] = 'OFF'

# Function to set all drives off
def MotorOff():
    GPIO.output(DRIVE_1, GPIO.LOW)
    GPIO.output(DRIVE_2, GPIO.LOW)
    GPIO.output(DRIVE_3, GPIO.LOW)
    GPIO.output(DRIVE_4, GPIO.LOW)

# Setup for sensors
#               [name,          terminal command to read the sensor,            multiplier],
lSensors = [
                ['Processor',   'cat /sys/class/thermal/thermal_zone0/temp',    0.001],
           ]

# Setup for individual fans, units for high / low are post multiplier
#           [drive,     sensor name,        low level 'off',    high level 'on'],
lFans = [
            [DRIVE_1,   'Processor',        31.0,               33.0],
            [DRIVE_2,   'Processor',        33.0,               35.0],
            [DRIVE_3,   'Processor',        35.0,               37.0],
            [DRIVE_4,   'Processor',        37.0,               39.0],
        ]

# Setup for processor monitor
interval = 1                                            # Time between readings in seconds

try:
    # Start by turning all drives off
    MotorOff()
    raw_input('You can now turn on the power, press ENTER to continue')
    # Add an extra field to each sensor for the latest reading
    for sensor in lSensors:
        sensor.append(0.0)
    # Change the fan configuration to use an index number, rather than a name
    for fan in lFans:
        found = False
        for i in range(len(lSensors)):
            if lSensors[i][0] == fan[1]:
                fan[1] = i
                found = True
                break
        if not found:
            print 'No sensor named "%s" listed!'
            sys.exit()
    while True:
        # Read the temperatures in from the various files
        for sensor in lSensors:
            fSensor = os.popen(sensor[1])
            sensor[3] = float(fSensor.read()) * sensor[2]
            fSensor.close()
            # Display the fan reading
            print '%s: %02.3f' % (sensor[0], sensor[3]),
        print ''
        # Go through each configured fan in turn
        for fan in lFans:
            sensor = lSensors[fan[1]]
            # Adjust the fan depending on current status
            if GPIO.input(fan[0]):
                if sensor[3] <= fan[2]:
                    # We have cooled down enough, turn the fan off
                    GPIO.output(fan[0], GPIO.LOW)
            else:
                if sensor[3] >= fan[3]:
                    # We have warmed up enough, turn the fan on
                    GPIO.output(fan[0], GPIO.HIGH)
        # Print the current state of all 4 drives
        print '%s %s %s %s' % (dName[GPIO.input(DRIVE_1)], dName[GPIO.input(DRIVE_2)], dName[GPIO.input(DRIVE_3)], dName[GPIO.input(DRIVE_4)])
        # Wait a while
        time.sleep(interval)
except KeyboardInterrupt:
    # CTRL+C exit, turn off the drives and release the GPIO pins
    print 'Terminated'
    MotorOff()
    raw_input('Turn the power off now, press ENTER to continue')
    GPIO.cleanup()
Subscribe to Comments for &quot;ChilledPi2 - Advanced fan control for keeping your Raspberry Pi cool&quot;