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.
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
rclone is another gem, its basically a fancy
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.
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.
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
feh -r /home/pi/Pictures/frame -D60 -F -z -Z --hide-pointer &
-ris to recursively look into the folder, e.g. in case there are subfolders
-Dis to set a delay in seconds between pictures
-Fis to fullscreen
-Zis auto-zoom, to fit screen nicely
-zis to randomise the file list. The random order then changes once
fehhas cycled through all the pictures in the folder
& 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:
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
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
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
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
</ troubleshooting interlude >
/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] Name=slideshow_start Exec=/home/pi/slideshow_start.sh Type=application
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
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.
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.
- Open a terminal and install the required software using the Raspbian package manager:
sudo apt install feh rclone
- Create a folder for your images
Add some images to the folder, or use the rclone instructions for your preferred storage system.
- Download the
slideshow_start.shscript in your home folder and modify the folder address to the path to your image folder and the params in the
fehcommand 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
- Download the
slideshow_start.desktopfile to your
autostartfolder to make the slideshow run at startup.
wget https://raw.githubusercontent.com/mearlboro/fehFrame/master/slideshow_start.desktop -P ~/.config/autostart
- If you’re using remote file storage, download the
slideshow_sync.shscript 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
Schedule the sync to happen every day at midnight by typing
crontab -eand 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.
- Reboot, wait a few seconds, and enjoy the show!