Choose your OS
Take a moment to decide which operating system you'd like to use. Consider the following limitations.
- Raspberry Pi OS has support for CircuitPython libraries and works with the 1.9in TFT screen for displaying GIFs and information like the Pi's IP address, CPU temperature, etc.
- Ubuntu variants but does not have support for CircuitPython libraries.
USB Boot with SSD
If you'd like to boot your Pi using an external SSD, you can follow along with the guide from Tom's Hardware. This process utilizes the full storage and features faster performance when reading/writing. This can be a good option for running a media server.
Install OS with Raspberry Pi Imager
Download the Raspberry Pi Imager and choose your preferred OS and method of booting.
If you're using Pi OS, click the gear icon to open advanced options. There you can enable SSH and configure wireless LAN.
Install CircuitPython Libraries
If you'd like to use the 1.9in TFT display, follow the installation guide to get setup.
TFT Display Info
Use the Python script below to display the IP address, CPU temperature and disk/memory usage. Make sure you have the fonts directory installed in the same directory as the Python script.
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT import subprocess import board import displayio from adafruit_display_text import label from adafruit_bitmap_font import bitmap_font from adafruit_st7789 import ST7789 BORDER_WIDTH = 4 TEXT_SCALE = 1 font = bitmap_font.load_font("/home/pi/fonts/Arial-18.bdf") font_small = bitmap_font.load_font("/home/pi/fonts/Arial-14.bdf") font_bold = bitmap_font.load_font("/home/pi/fonts/Arial-Bold-24.bdf") # Release any resources currently in use for the displays displayio.release_displays() spi = board.SPI() tft_cs = board.CE0 tft_dc = board.D25 tft_rst = board.D24 display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_rst) display = ST7789(display_bus, width=320, height=170, colstart=35, rotation=270) # Make the display context splash = displayio.Group() display.root_group = splash color_bitmap = displayio.Bitmap(display.width, display.height, 1) color_palette = displayio.Palette(1) color_palette[0] = 0xAA0088 # Purple bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0) splash.append(bg_sprite) # Draw a smaller inner rectangle inner_bitmap = displayio.Bitmap( display.width - (BORDER_WIDTH * 2), display.height - (BORDER_WIDTH * 2), 1 ) inner_palette = displayio.Palette(1) inner_palette[0] = 0x222222 # Dark Gray inner_sprite = displayio.TileGrid( inner_bitmap, pixel_shader=inner_palette, x=BORDER_WIDTH, y=BORDER_WIDTH ) splash.append(inner_sprite) # display ip, cpu and memory usage 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 = "vcgencmd measure_temp | grep -o -E '[[:digit:]].*'" cpu_temp = subprocess.check_output(cmd, shell=True).decode("utf-8") # Draw a label text_ip = label.Label( font_bold, text="IP: " + IP, color=0x1BF702, scale=TEXT_SCALE, ) text_cpu = label.Label( font, text="CPU: " + cpu_temp, color=0xFFFFFF, scale=TEXT_SCALE, ) text_mem = label.Label( font_small, text=MemUsage, color=0xCCCCCC, scale=TEXT_SCALE, ) text_ip.x = 12 text_cpu.x = 12 text_mem.x = 12 text_ip.y = 30 text_cpu.y = 70 text_mem.y = 150 splash.append(text_ip) splash.append(text_cpu) splash.append(text_mem) while True: text_ip.text = "IP: " + IP text_cpu.text = "CPU:" + cpu_temp text_mem.text = MemUsage display.refresh()
Download and copy the Python file to the home folder on your Raspberry Pi. Use the command in terminal to run the Python script: sudo nano python3 display-info.py
TFT Display GIF images
Use the python script below to display GIF images on the TFT display. You can use buttons to cycle through the images. Make sure you have the GIF images in a directory named GIFs. Ensure the python script is in a directory just outside the GIFs directory.
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT import os import time import digitalio import board from PIL import Image, ImageOps import numpy # pylint: disable=unused-import from adafruit_rgb_display import st7789 # pylint: disable=unused-import # Change to match your display BUTTON_NEXT = board.D17 BUTTON_PREVIOUS = board.D22 # Configuration for CS and DC pins (these are PiTFT defaults): cs_pin = digitalio.DigitalInOut(board.CE0) dc_pin = digitalio.DigitalInOut(board.D25) reset_pin = digitalio.DigitalInOut(board.D24) def init_button(pin): button = digitalio.DigitalInOut(pin) button.switch_to_input() button.pull = digitalio.Pull.UP return button # pylint: disable=too-few-public-methods class Frame: def __init__(self, duration=0): self.duration = duration self.image = None # pylint: enable=too-few-public-methods class AnimatedGif: def __init__(self, display, width=None, height=None, folder=None): self._frame_count = 0 self._loop = 0 self._index = 0 self._duration = 0 self._gif_files = [] self._frames = [] if width is not None: self._width = width else: self._width = display.width if height is not None: self._height = height else: self._height = display.height self.display = display self.advance_button = init_button(BUTTON_NEXT) self.back_button = init_button(BUTTON_PREVIOUS) if folder is not None: self.load_files(folder) self.run() def advance(self): self._index = (self._index + 1) % len(self._gif_files) def back(self): self._index = (self._index - 1 + len(self._gif_files)) % len(self._gif_files) def load_files(self, folder): gif_files = [f for f in os.listdir(folder) if f.endswith(".gif")] for gif_file in gif_files: gif_file = os.path.join(folder, gif_file) image = Image.open(gif_file) # Only add animated Gifs if image.is_animated: self._gif_files.append(gif_file) print("Found", self._gif_files) if not self._gif_files: print("No Gif files found in current folder") exit() # pylint: disable=consider-using-sys-exit def preload(self): image = Image.open(self._gif_files[self._index]) print("Loading {}...".format(self._gif_files[self._index])) if "duration" in image.info: self._duration = image.info["duration"] else: self._duration = 0 if "loop" in image.info: self._loop = image.info["loop"] else: self._loop = 1 self._frame_count = image.n_frames self._frames.clear() for frame in range(self._frame_count): image.seek(frame) # Create blank image for drawing. # Make sure to create image with mode 'RGB' for full color. frame_object = Frame(duration=self._duration) if "duration" in image.info: frame_object.duration = image.info["duration"] frame_object.image = ImageOps.pad( # pylint: disable=no-member image.convert("RGB"), (self._width, self._height), method=Image.Resampling.NEAREST, color=(0, 0, 0), centering=(0.5, 0.5), ) self._frames.append(frame_object) def play(self): self.preload() _prev_advance_btn_val = self.advance_button.value _prev_back_btn_val = self.back_button.value # Check if we have loaded any files first if not self._gif_files: print("There are no Gif Images loaded to Play") return False while True: for frame_object in self._frames: start_time = time.monotonic() self.display.image(frame_object.image) _cur_advance_btn_val = self.advance_button.value _cur_back_btn_val = self.back_button.value if not _cur_advance_btn_val and _prev_advance_btn_val: self.advance() return False if not _cur_back_btn_val and _prev_back_btn_val: self.back() return False _prev_back_btn_val = _cur_back_btn_val _prev_advance_btn_val = _cur_advance_btn_val while time.monotonic() < (start_time + frame_object.duration / 1000): pass if self._loop == 1: return True if self._loop > 0: self._loop -= 1 def run(self): while True: auto_advance = self.play() if auto_advance: self.advance() # Config for display baudrate (default max is 64mhz): BAUDRATE = 64000000 # Setup SPI bus using hardware SPI: spi = board.SPI() disp = st7789.ST7789( spi, rotation=270, width=170, height=320, x_offset=35, cs=cs_pin, dc=dc_pin, rst=reset_pin, baudrate=BAUDRATE, ) # pylint: enable=line-too-long if disp.rotation % 180 == 90: disp_height = disp.width # we swap height/width to rotate it to landscape! disp_width = disp.height else: disp_width = disp.width disp_height = disp.height gif_player = AnimatedGif(disp, width=disp_width, height=disp_height, folder="gifs")
Download and copy the Python file to the home folder on your Raspberry Pi. Use the command in terminal to run the Python script: sudo nano python3 gif-player.py
Autostart TFT python scripts
Create an autostart script to enable the TFT display automatically on boot. Start by creating a new file with this command.
sudo nano /lib/systemd/system/tftdisplay.service
Copy the text below and paste it into the new file. Check the .py file is in the correct directory. You may need to modify the path if you've changed the Pi's hostname or title of Python script.
[Unit] Description=TFT Display Service After=multi-user.target [Service] Type=idle ExecStart=/usr/bin/python /home/pi/tft-display.py [Install] WantedBy=multi-user.target
Save this file and exit the editor. A few commands then enable this new service and will launch it on startup:
sudo systemctl daemon-reload sudo systemctl enable tftdisplay.service sudo reboot
To change which program is loaded on startup, just edit /lib/systemd/system/tftdisplay.service and change the ExecStart line, and reboot. No need to repeat the systemctl commands.
Enable Safe Shutdown
You can use the metal push button to safely shutdown your Pi. Add a line to the config.txt file using the sudo nano /boot/config.txt
command in terminal.
In the circuit diagram, the metal push button is wired to both GPIO3 and GPIO27. By default, ground and GPIO3 will power up the Pi. GPIO27 is used to safely shutdown the Pi.
dtoverlay=gpio-shutdown,gpio_pin=27,active_low=0
Save the config.txt file and exit the editor. Reboot the Raspberry Pi and the pressing the power button should run the safe shutdown service.
Install Plex Media Server
If you'd like to use the Pi as a media center, you can install Plex on the Raspberry Pi. This will use the Chromium web browser to display the Plex interface where you can play and stream media.
Head over to the plex website and choose Linux as the platform and then click Choose Distribution. Select the Ubuntu ARM (v7 for 32-bit Pi OS) and download.
Once downloaded, double-click the file to install the software. When complete, Head over to localhost:32400/web/ where you should see the Plex log in screen. There you can configure your settings and add media.
Follow along with the Basic Setup Wizard guide from Plex for more documentation on configuring your settings.
Autostart Chromium in Full Screen Kiosk Mode
You can launch Chromium in full screen mode by adding a line to the autostart file on the LXDE desktop. Run the following command in terminal to edit the configuration file.
sudo nano /etc/xdg/lxsession/LXDE-pi/autostart
Modify the autostart file by adding the line below and save with key combination Ctrl+ X then Y.
@lxpanel --profile LXDE-pi @pcmanfm --desktop --profile LXDE-pi @xscreensaver -no-splash /usr/bin/chromium-browser --kiosk --disable-restore-session-state http://localhost:32400/web/
Reboot the Raspberry Pi to test the updated autostart file. Chromium will automatically open and display the Plex interface by loading the http://localhost:32400/web/ website.
Text editor powered by tinymce.