For the last year and a half, I have been iterating through different versions of a Raspberry Pi cluster. There is a ton of information I want to share about the cluster, but for now, let’s focus on how I keep it cool.

A little background first. The Pi cluster takes up 2U at the back of my rack and is sandwiched between my EdgeSwitch 48-Lite and EdgeSwitch 16 PoE. The Pis are all powered via PoE HATs. The PoE HATs significantly reduce cable clutter, and they also include a 25 × 25 mm fan to keep each Pi cool. The only downside is that the 25 mm fan is obnoxiously loud at full speed. Multiply that across seven Pis, and you can definitely tell when the fans have spun up.

Seven Raspberry Pis mounted between two EdgeSwitches at the back of the rack
The Pi cluster at the back of the rack, squeezed between the switches.

I decided to add some fans to my rack to help keep the cluster cool and quiet. I already had the fans lying around, and all the other parts were easy to acquire and piece together.

Parts list

  1. Adafruit EMC2101 I2C PC Fan Controller and Temperature Sensor
  2. SparkFun Stemma QT SHIM
  3. Raspberry Pi Zero W
  4. Noctua NA-FC1, 4-Pin PWM Fan Controller
  5. Three 120 mm NZXT fans left over from my recent PC build.

Control script

The control script is pretty basic.

Show the Python control script
# SPDX-FileCopyrightText: 2020 Bryan Siepert, written for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import time
import board
import sys
from subprocess import PIPE, Popen
from adafruit_emc2101 import EMC2101

i2c = board.I2C()  # uses board.SCL and board.SDA
emc = EMC2101(i2c)

emc.manual_fan_speed = 10

def getCPUTemp():
    process = Popen(['vcgencmd', 'measure_temp'], stdout=PIPE)
    output, _error = process.communicate()
    decoded = output.decode('UTF-8')
    return float(decoded[decoded.index('=') + 1:decoded.rindex("'")])

def main():
    while True:
        currentTemp = getCPUTemp()
        print("Current Temp: {}".format(currentTemp))
        print("Fan Speed: {}".format(emc.fan_speed))
        if currentTemp > 40.0:
            print("Setting fan speed to {}".format("40"))
            emc.manual_fan_speed = 40
        else:
            print("Setting fan speed to {}".format("30"))
            emc.manual_fan_speed = 30
        time.sleep(60)


if __name__ == "__main__":
    main()

Systemd service

It runs as a systemd service, so I don’t have to worry about starting it manually.

Show the systemd service
[Unit]
Description=Pi Fan Control Service

[Service]
Environment=PYTHONUNBUFFERED=1
ExecStart=/usr/bin/python3 -u /usr/sbin/control.py
Restart=on-failure

[Install]
WantedBy=default.target

The finished setup

Raspberry Pi Zero W with the fan controller board mounted in a black bracket
The Pi Zero W and fan controller board. It slots into the Pi cluster rack
Two NZXT fans and a Noctua fan controller zip-tied to the rack door
Fans zip-tied to the rack door, because why not?
The rack doors closed with the cooling fans visible behind the mesh
The finished setup with the rack doors closed. Air blows directly onto the switches and Pi cluster

If I were smart, I would’ve taken temperature readings before and compared them with readings afterward. I didn’t, so you’ll have to take my word that things are much quieter and cooler now!