An open-source digital picture frame using RaspberriPi, a screen, and picture viewer feh

The fehFrame yet another open-source digital picture frame. Many such projects exist but as far as I have looked this is the simplest. There are many alternatives and extra functionalities one can achieve, but they seemed to be quite complicated and/or use a lot of unnecessary code.

This takes moments to setup and only uses Linux utilities. Just drawing some cables and running some commands.

Setting this up I did encounter some hiccups and errors but I learned some things in the process so I thought I’d document it here and share the “code” (which is truly and embarrasingly short).

Continue reading for the full saga of errors and troubleshooting steps or feel free to skip straight to the Instructions.



The original hardware was put together by my flatmate A., who doesn’t own a tablet, but needed a device to read large format illustrated books on.

To do the same, you will need:

  • a RaspberryPi (connected to the Internet)
  • a screen
  • a cable to connect the screen to the Pi
  • a power supply for the screen
  • a power supply for the Pi

This works with any Pi you may have lying around and any screen. Depending on your hardware you may need different cables so I’ll keep this purposefully vague. It actually works with anything that can run Linux and connect to a screen.



Later on A. wanted to use the same screen as a slideshow of movie stills. Two websites with movie stills are FilmGrab and Stills database.

The only thing needed to put this together was a couple of open source projects and writing a few commands, introduced below.


The fehFrame relies on the Linux command-line picture viewer feh to display images located in a specific folder as a slideshow.

I recommend playing with feh a little, as it’s truly a poweful tool. I discovered it when I started using i3wm as part of the suite of command-line productivity tools that usually get recommended for it. I now use feh to play with my “desktop” background and to look at pictures (locally or remote). You can learn more about feh in the Archwiki or man feh.


rclone is another gem, its basically a fancy scp or rsync. Some of its extra features are a flag to show progress of the copying, verification, and a very seamless process to connect to external cloud accounts (e.g. Dropbox, Google Drive etc) or even your own home filesystem or FTP server with your own authentication. rclone supports many different storage systems and I recommend you first read more about how to set it up with yours.


cron is the main tool used to schedule tasks on Linux, either at specific times, intervals, or following events such as a reboot. cron keeps all the scheduled tasks in a cron table or crontab. There is a system-wide crontab that lives in /etc/crontab but usually each user configures their own.

The command crontab -e only opens the current user’s file in your preferred text editor, where you can just add your scheduled task. cron has a simple yet sometimes misleading syntax. The most frequently used cron table entry begins with a group of 5 numbers or stars (*) separated by spaces, which indicate the time when the command needs to be run, then continues with the command to be run.

I warmly recommend the site crontab.guru for understanding and verifying crons.


The process

Slideshow with feh

I took some time to play with the slideshow parameters until I produced this command, which starts the slideshow straight away and loops randomly through all pictures located in /home/pi/Pictures/frame

feh -r /home/pi/Pictures/frame -D60 -F -z -Z --hide-pointer &


  • -r is to recursively look into the folder, e.g. in case there are subfolders
  • -D is to set a delay in seconds between pictures
  • -F is to fullscreen
  • -Z is auto-zoom, to fit screen nicely
  • -z is to randomise the file list. The random order then changes once feh has cycled through all the pictures in the folder

Note & at the end is to fork the process, i.e. to start the application detached from the current terminal session.

I suggest to play with other parameters listed in man feh in order to achieve the slideshow effect that you are aiming for. feh also supports transitions and something called montage mode. How much nicer this is than actually writing a script that displays the images.

Run slideshow at startup

To make this feel seamless, the slideshow should start as soon as the device is booted without further interaction for the user. First, I added the command above to a script slideshow_start.sh so I can easily reuse it, and made it executable:

chmod +x slideshow_start.sh

Now how to run something at startup? There are many ways and before I did this project it wasn’t yet clear to me what is the difference between them. The section below describes my process of discovering what to use. It was quite educational for me, but if you don’t care you can skip straight to the Instructions at the end


< troubleshooting interlude >

I started with a scheduled task using @reboot to tell cron I want my script to run at reboot. So I ran crontab -e and typed:

@reboot /home/pi/slideshow_start.sh

And I rebooted, and it didn’t work. Thus I realised there is some difference in Linux between software that runs in the background (e.g. daemons, such as cron) which is non-graphical and non-interactive, and software that runs in the foreground which can be both graphical and interactive (in our case feh). Therefore, cron would not know exactly how to communicate with the Xorg server which manages the graphical session (or X session) to spawn an instance of feh.

After a little web searching I thought I could give Xorg a hand by setting some environment variables needed to start a graphical app in the cron command, specifically to tell it which monitor to use and pass in the credentials that confirm to Xorg that cron has the authority to run an Xorg app (that’s the XAUTHORITY, a file that lives in the user’s home directory and is used to store credentials for authentication of X sessions).

@reboot DISPLAY=:0.0 XAUTHORITY=/home/pi/.Xauthority /home/pi/slideshow_start.sh

But this didn’t work either and I have no idea why. Diving into this I could only discover how shabby the Xorg system is. Take this Xauthority file, which holds my credentials to authenticate into the server that runs all my GUIs. No matter how much I secure my individual applications and compartmentalise my system, Xorg put all my eggs back in one basket. My X session is a monolithic threat at the core of everything I do on Linux. Although I was aware of some known vulnerabilities of Xorg, exploring this further was a chilling way to acknowledge its fragility. My mate mkinitbtcio has pointed this out to me for a while, as he’s already started playing with alternatives for Xorg such as Wayland, but alas, that’s enough off-topic ranting for now.

Then I thought, another way to run things at startup is when initialising the shell. Every time a terminal session starts the configuration for the user’s shell in .bashrc is one of the first things to run. Therefore I figured one could also use that to run my script, by adding a line /home/pi/slideshow_start.sh to /home/pi/.bashrc.

And this didn’t work either, or it only worked partially, as the slideshow would only start the moment I opened a terminal. Because a script is executed by a non-interactive shell, while .bashrc is only automatically sourced by interactive shells.

Next, I tried the RaspberryPi way to start an application at startup, using the file /etc/rc.local. As the Pi documentation suggested I added my script to the file before the exit 0 line, but that did not work either. I suspect this is because all rc.local commands are run as sudo, and the sudo user does not have the paths and configuration I prefer for my own user.

After going through all of this I figured that most methods I tried were either for non-interactive or non-graphical tasks. But there is a standard way to handle graphical tasks: the autostart folder.

</ troubleshooting interlude >


The /home/pi/.config/autostart folder contains user-specific startup programs, similar to the Startup folder in Windows. These are listed as .desktop files with a specific structure. Mine is

[Desktop Entry]

I saved it as slideshow_start.desktop, rebooted, and it worked. Just for the sake of avoiding errors, I also recommend waiting a little before starting the slideshow, by adding sleep 10 & before the feh command in slideshow_start.sh

Scheduled sync

Finally, I used rclone to sync the pictures displayed by feh from an external file storage. A. stores the images on his google drive and occasionally adds or removes some, so I used the instructions and it worked straight away. He also wanted the images to sync daily and to “hot-swap” the images without having to restart the slideshow.

First I added the rclone command to a script, but only after deleting all the pictures from the folder (since rclone copy does not handle deletion of files, only addition). Thankfully feh detects when the folder’s contents have changed and shows the updated images without requiring a restart.

And just to track down if the scheduling will work well, I also added output to a log file.

rm -rf /home/pi/Pictures/frame/*
/usr/bin/rclone copy gdrive:Pictures/frame /home/pi/Pictures/frame
echo "`date`: Done sync" > /home/pi/Pictures/fehframe.log

For the daily sync, I saved this as slideshow_sync.sh then added it to my crontab. The job will run daily at midnight.

    0 12 * * * /home/pi/slideshow_sync.sh


This now sits in our living room, looping through movie stills, constantly distracting us with their beauty, and sometimes we play the game “What film is this from?” although I always lose.



  1. Considering you’ve put the Pi together with the screen and it boots, you’re good to go! You can choose to attach a mouse and keyboard to the Pi or SSH into it, up to you.

  2. Open a terminal and install the required software using the Raspbian package manager:
    sudo apt install feh rclone
  3. Create a folder for your images
    mkdir ~/Pictures/frame
  4. Add some images to the folder, or use the rclone instructions for your preferred storage system.

  5. Download the slideshow_start.sh script in your home folder and modify the folder address to the path to your image folder and the params in the feh command for your preferred slideshow, then make it executable:
    cd ~
    wget https://raw.githubusercontent.com/mearlboro/fehFrame/blob/master/slideshow_start.sh
    chmod +x slideshow_start.sh
  6. Download the slideshow_start.desktop file to your autostart folder to make the slideshow run at startup.
    wget https://raw.githubusercontent.com/mearlboro/fehFrame/master/slideshow_start.desktop -P ~/.config/autostart
  7. If you’re using remote file storage, download the slideshow_sync.sh script in your home folder and modify the folder addresses to point to your remote and local locations for the images, then make it executable:
    wget https://raw.githubusercontent.com/mearlboro/fehFrame/blob/master/slideshow_sync.sh
    chmod +x slideshow_sync.sh
  8. Schedule the sync to happen every day at midnight by typing crontab -e and pasting the following code on its own line at the beginning 0 12 * * * /home/pi/slideshow_sync.sh. You can use crontab.guru to help you program a different time or frequency for running the task.

  9. Reboot, wait a few seconds, and enjoy the show!