Adam's blog: Cat-proofing the Raspberry Pi

30 Apr 2023, 1686 words

At my girlfriend’s place, I have a RPi 4 server with an old external 1.5TB HDD attached. To protect the hardware from her furry pets. I had to place the server inside a big cardboard box filled with plastic air bubbles and hide the box itself under the nightstand. This setup, as time had shown, was not without flaws.

It’s hot & loud

First, imagine a computer in a closed tight space with active USB ports. Such instalment inevitably leads to overheating. Overheating can be solved by adding a passive cooler and an official RPi fan, nice!

Photo of Raspberry Pi with the official fan installed

Not a “fan” of high tempeature

Oops, the fan is really loud with quite a high pitch, which makes sleeping in the same room almost unbearable. To lower the time with the fan on, let’s write a simple script (…because the RPi is running Ubuntu and raspi-settings is not available here…) that will turn the fan only when the CPU temperature reaches a certain threshold:

#!/usr/bin/python3

from os import system
from gpiozero import LED
from time import sleep

FAN_PIN = 14
FILE_TEMP = "/sys/class/thermal/thermal_zone0/temp"
TEMP_MAX = 75
TEMP_COOLDOWN = 65

print(f"The fan will start when the tempeature is over {TEMP_MAX} degrees", flush=True)

fan = LED(FAN_PIN)
cool = False

while True:
    try:
        with open(FILE_TEMP, 'r') as f:
            temp = int(f.read()) // 1000
        if temp >= TEMP_MAX:
            if not cool:
                print(f'Fan ON, {temp}', flush=True)
            cool = True
        if temp <= TEMP_COOLDOWN:
            if cool:
                print(f'FAN OFF, {temp}', flush=True)
                cool = False
        if cool:
            fan.on()
        else:
            fan.off()
    finally:
        sleep(3)

This makes the noise problem almost disappear, but still, when the load would get high enough (e. g. when multiple phones would start backing up their photos at the same time), the temperature could grow over the threshold and start the fan in the middle of the night. I must note, that the setup was active in this form for a few years and I am truly sorry.

Governor!

I figured out that I need to take matters more closely into my hands. From the forums, I was able to deduct that the RPi itself starts to slow down CPU speed, but in, for me unpractically high, temperature. Fortunately, I could switch the CPU governor to manual and force it to run at the lowest possible clock speed:

#!/usr/bin/python3

from os import system
from gpiozero import LED
from time import sleep

FAN_PIN = 14
FILE_TEMP = "/sys/class/thermal/thermal_zone0/temp"
TEMP_MAX = 75
TEMP_CPU_SLOWDOWN = 67
TEMP_COOLDOWN = 65

print(f"The fan will start when the tempeature is over {TEMP_MAX} degrees, the CPU will slow down at {TEMP_CPU_SLOWDOWN} degrees", flush=True)

fan = LED(FAN_PIN)
system('cpufreq-set -g ondemand')
cool = False
slow = False

while True:
    try:
        with open(FILE_TEMP, 'r') as f:
            temp = int(f.read()) // 1000
        if temp >= TEMP_MAX:
            if not cool:
                print(f'Fan ON, {temp}', flush=True)
            cool = True
        if temp >= TEMP_CPU_SLOWDOWN:
            if not slow:
                print(f'CPU SLOW, {temp}', flush=True)
                slow = True
            system('cpufreq-set -g userspace')
            system('cpufreq-set -rf 600M')
        if temp <= TEMP_COOLDOWN:
            if cool:
                print(f'FAN OFF, {temp}', flush=True)
                cool = False
            if slow:
                print(f'CPU normal, {temp}', flush=True)
                system('cpufreq-set -g ondemand')
                slow = False

        if cool:
            fan.on()
        else:
            fan.off()
    finally:
        sleep(3)

Furthermore, I have added maxcpus=2 to the /boot/firmware/cmdline.txt file, so only 2 out of 4 CPU cores were enabled. These two modifications have reduced the frequency of fan starts but still would run if the CPU load stayed high for long enough. This was because the Pi still was placed inside a small box. To resolve this, I would have to place the Pi into a more open space.

Then it clicked

The RPi was now perfectly quiet, but still, one source of the noise remained – during every write, the HDD would give out a (semi-)loud clicking sound, which was utterly annoying (but still lasted several years, I really am sorry). First, I tried some software-based solutions:

  1. set BTRF’s commit interval to 5 minutes, with the idea behind it being that it would write all data only once in a while and would not click that much. As you can imagine, this resulted in a data loss after power loss on more than one occasion
  2. use FUSE-based fs that would cache the data on the internal SD card and after the specified interval would move the data to the HDD. This option resulted in a considerable performance loss and wore off the internal SD card rather quickly

Besides, neither of the options solved the initial clicking problem, only delayed it. The only possible solution was to replace the HDD with an SSD. After a bit of research and setting up an RSS notification for /r/buildapcsales, I have found out that Patriot makes nice and cheap 2TB discs. That, combined with a case, made for a simple and working external SSD.

A new adversary

My SO’s new addition to the pet family got bigger and better (at moving the cardboard box containing the RPi), which poses a new threat to the data integrity, as cats are not known for their carefulness with anything they consider a toy.

Photo of my new adversary, Lucifer

Moreover, even when he did not try to move some boxes while nobody was looking, Lucifer still left quite a large load of furr everywhere he went, which did not seem exactly healthy for any electronic devices. Any form of placing the Pi in a freely accessible spot would now equal hazarding its life. I had to find a space open enough so that the air would circulate properly and that the cat won’t be able to reach it.

New setup

Luckily, my SO has one of the tables with space for cables that was wide enough for the Pi to fit in. Furthermore, because the network in her house is wireless only with some devices running untrustworthy software, I saw this as a great opportunity to create a custom wired network where the Pi would act as a router, safe from all untrusted devices, so I hooked the Pi with a cheap 4-port 100 Mbit/s switch.

Photo of Pi and other electronics hidden inside a table

Even though acceptable in theory, the air circulation was not good enough to keep the Pi from overheating and, in the end, it made the situation more harmful. Even worse, it turned out that the Pi’s plastic case itself was unable to decrease its temperature quickly enough.

After a while, I decided to place the Pi between the supports for the shelf above the table. And, because bright red and white would appear too distracting, I have decided to purchase a new case made of metal. This could act as a supplementary layer of passive cooling. Even though it hadn’t a dedicated spot to hold the fan, I was able to attach the fan with a few wires through the gaps in the upper part of the case. Then, I positioned the SSD on the opposite end of the shelf and arranged all cables inside the table together with the switch (which does not suffer from overheating).

Photo of Pi and SSD under the shelf

Final words

After everything was finished and I sacrificed the USB 3 speed in favour of WiFi, I now have a server setup which provides a safe ethernet network to all devices. Based on logs (and my SO’s experience) there was not a single fan run in a few months (except after a power loss during a thunderstorm). Furthermore, there were no cat-related incidents, because none of the pets is allowed on the table and even if they disregard this rule, they have never paid any attention to the black box attached to a wall.