Rack mount success

Of late we have been playing around with Rack mounting of Raspberry Pi’s to form a small scale development lab for one of our clients. Initially designs of the Rack mount didn’t suit what we required. We needed to be able to see at a glance the Hostname, IP Address and general stats of the Raspberry Pi as it was under load.

Most of the designs for rack mounting of Raspberry Pi’s relied upon the purchase of specialty rack mounting kits or the printing of a large number of mounts that didn’t include the ability to have OLED displays attached.

Then we found this https://www.prusaprinters.org/prints/69176-1u-raspberry-pi-rack-with-moduler-trays/files

Working closely with the developer of this rack we where not only able to rack mount up all our Raspberry Pi 3B+ but also the 4 using the Raspberry Pi PoE Hat and most recently the PoE+ Hat.

Next came the Configuration of the OLED displays to ensure that they worked correctly. The obvious choice was to use Python. As you can see by the above image (even though the display wasn’t mounted properly at this point) the OLED display shows the IP address, CPU load etc. Initially we went with the standard python script that comes as part of the Adafruit CircuitPython SSD1306 library https://github.com/adafruit/Adafruit_CircuitPython_SSD1306/blob/main/examples/ssd1306_stats.py however we found that it was limited in a few ways – least of all us older, half blind technicians that need to see the display couldn’t read the small print. So guess what… we modified it and added our own spin on it.

# SPDX-FileCopyrightText: 2017 Tony DiCola for Adafruit Industries
# SPDX-FileCopyrightText: 2017 James DeVito for Adafruit Industries
# SPDX-License-Identifier: MIT

# This example is for use on (Linux) computers that are using CPython with
# Adafruit Blinka to support CircuitPython libraries. CircuitPython does
# not support PIL/pillow (python imaging library)!

import time
import subprocess

from board import SCL, SDA
import busio
from PIL import Image, ImageDraw, ImageFont
import adafruit_ssd1306


# Create the I2C interface.
i2c = busio.I2C(SCL, SDA)

# Create the SSD1306 OLED class.
# The first two parameters are the pixel width and pixel height.  Change these
# to the right size for your display!
disp = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)

# Clear display.
disp.fill(0)
disp.show()
disp.rotate(2)

# Create blank image for drawing.
# Make sure to create image with mode '1' for 1-bit color.
width = disp.width
height = disp.height
image = Image.new("1", (width, height))

# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)

# Draw a black filled box to clear the image.
draw.rectangle((0, 0, width, height), outline=0, fill=0)

# Draw some shapes.
# First define some constants to allow easy resizing of shapes.
padding = -2
top = padding
bottom = height - padding
# Move left to right keeping track of the current x position for drawing shapes.
x = 0


# Load default font.
#font = ImageFont.load_default()

# Alternatively load a TTF font.  Make sure the .ttf font file is in the
# same directory as the python script!
# Some other nice fonts to try: http://www.dafont.com/bitmap.php
font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', 16)
z = 0
while True:

    # Draw a black filled box to clear the image.
    draw.rectangle((0, 0, width, height), outline=0, fill=0)

    # Shell scripts for system monitoring from here:
    # https://unix.stackexchange.com/questions/119126/command-to-display-memory-usage-disk-usage-and-cpu-load
    cmd = "hostname -I | cut -d' ' -f1"
    IP = subprocess.check_output(cmd, shell=True).decode("utf-8")
    cmd = 'cut -f 1 -d " " /proc/loadavg'
    CPU = subprocess.check_output(cmd, shell=True).decode("utf-8")
    cmd = "free -m | awk 'NR==2{printf \"Mem: %s/%s MB  %.2f%%\", $3,$2,$3*100/$2 }'"
    MemUsage = subprocess.check_output(cmd, shell=True).decode("utf-8")
    cmd = 'df -h | awk \'$NF=="/"{printf "Disk: %d/%d GB  %s", $3,$2,$5}\''
    Disk = subprocess.check_output(cmd, shell=True).decode("utf-8")
    cmd = "hostname"
    host = subprocess.check_output(cmd, shell=True).decode("utf-8")


    # Write four lines of text.
    if z == 0:
        draw.text((x, top + 0), "Hostname", font=font, fill=255)
        draw.text((x, top +16), host, font=font, fill=255)
        z = 1
        time.sleep(2)
    elif z == 1:
        draw.text((x, top + 0), "IP: " + IP, font=font, fill=255)
        draw.text((x, top +16), "CPU: " + CPU, font=font, fill=255)
        z = 2 
        time.sleep(2)
    else:
        draw.text((x, top + 0), MemUsage, font=font, fill=255)
        draw.text((x, top + 16), Disk, font=font, fill=255)
        z=0
        time.sleep(2)
    # Display image.
    disp.image(image)
    disp.show()
    time.sleep(0.1)


As you can see it is based off the original package script and we have left the copyright details in there to ensure compliance.

Obviously this script doesn’t just work out of the box. There are a few things that need to be done to ensure that it works properly. Follow the steps below on how to do this correctly and avoid the mistakes we made on the journey.

Firstly – Ensure you have updated your Raspberry Pi installation

sudo apt-get update
sudo apt-get upgrade

Then run the Raspberry Pi configuration tool

sudo raspi-config

I would recommend going through the basic system configurations if you havn’t already and ensuring that they are configured to your requirements (change hostname, enable wi-fi country etc). If you are running this as a headless device i.e. not attaching to a screen once mounted – ensure that you enable ssh in the Interface options. I would also recommend that on a headless unit you do not need to allocate a lot of memory to the GPU so under Performance Options adjust that there to be 16MB for example as Text does not use up much CPU memory – better off having the extra memory for your applications down the track.

Next i installed a True Type Font to give me a much nicer looking display. I personally chose to use the one from Font Squirrel however the choice is yours – https://www.fontsquirrel.com/fonts/dejavu-sans

This needs to be unzipped and put into the appropriate directory as per below

cd ~
mkdir temp
cd temp
wget https://www.fontsquirrel.com/fonts/download/dejavu-sans
mv dejavu-sans dejavu-sans.zip
unzip dejavu-sans.zip
sudo mkdir -p /usr/share/fonts/truetype/dejavu
cp DejaVuSans.ttf /usr/share/fonts/trutype/dejavu

OK. This is the important part now. You need to enable to SPI and the I2C interfaces on your Pi so that the OLED display will work correctly. There are 2 seperate Interface Options (option 3) that you need to enable to make this work.

Enable both P4 and P5 in this menu.

Once this is done you will need to reboot your Pi and then install the following packages.

sudo apt-get update
sudo apt-get install -y python3-pip
sudo pip3 install adafruit-circuitpython-ssd1306
sudo apt-get install -y python3-pil
sudo apt-get install -y python3-smbus
sudo apt-get install -y i2c-tools
sudo pip3 install psutil

I really do recommend rebooting after this installation. I have seen it twice where for whatever strange reason the Python script didn’t work until rebooted… couldn’t explain it just happened.

Right – now to the Nitty Gritty part – Open up either Vi or Nano whatever your poison is for an editor and copy/paste the above Python script into the file and in my systems i save them as /home/pi/stats.py . You can run it to test by using the below command

python3 /home/pi/stats.py

If all goes well you should see the stats of your local pi working on the OLED display. If an error is displayed by the Python interpreter you need to check for typo’s and missing files such as the Font etc.

Once you have the display working you want to ensure that once you reboot it comes back up correctly. To achieve this you will need to edit the /etc/rc.local and add the following line – again use your favourite editor to do this. Make sure you put it directly ABOVE the exit 0 line or it will not run.

sudo python3 /home/pi/stats.py &

There you go… reboot and check that it comes back up with the display. We now have a number of these rack mounted Raspberry Pi’s using OLED displays. We will be deploying several more over the coming weeks as we complete each print for the rack mount and each individual Module for the Pi’s. At this point we have approx 4 Raspberry Pi 3B+, 5 Raspberry Pi 4’s and one Pi Zero in place. We are working with the developer of the Rack Mount kit to eventually have the Compute Module 4 plus the I/O board mounted into one of these as well… This will be another post as it is quite a fun project.