====== A digital frame with the Raspberry Pi ======
**Digital frames** have become common gadgets, easily available in electronics stores or online. Unfortunately they came with proprietary software, and limited flexibility. So my choice was to purchase a nice 24 inches monitor and boundle it with a **Raspberry Pi 2**, fitted with a **64 Gb SD card**.
For the software part I opted for a **web based** user interface written in **PHP**, which allow to easily browse all the **pictures organized in directories**. Each directory containing images have a **playlist.m3u** file, which lists the files to be shown in the slideshow. The playlist file contains also geometry information to re-frame the pictures to fit the screen as requested. So I can show photos taken in **4:3** ratio on the **16:9 screen**, without the **black borders**. All the magic of the slideshow is accomplished by the **[[https://github.com/RigacciOrg/photo-reframe-slideshow|photo-reframe-slideshow]]** software.
{{.:raspberrypi:digital-frame.jpg?512|The Raspberry Pi Digital Frame}}
In the picture above you can see the final assembly. The monitor is a **Philips 243V7QJABF, 24 inches LED IPS** capable of **1920x1080** resolution, the software runs on the **Raspberry Pi 2 Model B Rev 1.1**, using a **64 Gb SD card**.
===== Building the frame =====
The first step was to order the hand-made **wood frame** from a craftsman. The profile size is shown in the picture, the inner space to accommodate the monitor is **54.0 x 32.5 cm**.
{{ .:raspberrypi:frame-profile.png?280 |Wood Frame Profile}}
I made **two aluminum brackets** suitably drilled and bent to connect the frame and the monitor, using the **Vesa mount holes**.
{{ .:raspberrypi:digital-frame-brackets.jpg?480 |Aluminium brackets}}
{{ .:raspberrypi:digital-frame-back.jpg?480 |Raspberry Pi Digital Frame: back}}
I used some **electrical wiring**, clamps and heat-shrink tubing to provide the power. The Raspberry Pi **power supply** is glued to the monitor back with a bit of **silicone adhesive**. A few pieces of **felt and a cloth** were used as padding to prevent the metal from dirtying the wall. Finally a bit of electrical cable was used to make **the hanging hook**, built so that the angle of the frame could be adjusted downwards.
{{ .:raspberrypi:digital-frame-cabling.jpg?480 |Power supply for the Monitor and the Raspberry Pi}}
I had to cut some of the wooden frame to **allow access to the monitor buttons**, as you can see from the photograph of the detail. The **Raspberry Pi** is mounted with wood screws, an insulating plastic sheet and spacers made with rubber tube.
{{.:raspberrypi:digital-frame-wood-cut.jpg?260|Wood cut to expose the buttons}}
{{.:raspberrypi:digital-frame-buttons.jpg?260|Monitor buttons}}
{{.:raspberrypi:digital-frame-raspberry-mount.jpg?260|Raspberry Pi mounting}}
===== Tip to improve =====
As you can see from the final assemble, the **bottom frame** of the monitor is higher than the wood frame, so a **black stripe** remains visible at the bottom. It would have been better to make a **passepartout all around** the monitor to hide that difference.
===== photo-reframe =====
The **software core** of the digital frame is the **[[https://github.com/RigacciOrg/photo-reframe-slideshow|photo-reframe-slideshow]]** program. Its main feature is the ability to show pictures at a specific **zoom** and **pan** points, without requiring to actually cut the original pictures. You upload the original pictures along a **playlist** file, which contains the re-frame options to be applied on the fly.
===== CheatSheet =====
Here it is a **Cheat Sheet** to be printed on a 7x7 cm sticker and attached below the **wireless keyboard**. Some shortcuts are related to the **photo-reframe** program, others are related to the **XFCE** desktop (default and custom shortcuts).
^ Space | Immagine successiva |
^ Backspace | Immagine precedente |
^ P | Avvia o ferma la presentazione |
^ C | Mostra o nasconde il commento |
^ I | Mostra o nascondi le info |
^ +/- | Aumenta o diminuisce lo zoom |
^ Frecce | Panoramica |
^ Esc / Q | Esci |
^ F1 | Help |
^ F2 | Condividi via email |
^ Ctrl-Q | Poweroff, Reboot, etc. |
^ Alt-F1 | XFCE Menu |
^ Alt-F2 | Run program |
===== RaspiOS customization =====
I downloaded and installed **RaspiOS 2020-05-27 Buster**, based on Debian 10. I choosed the **full** version "with desktop and recommended software".
==== WiFi ====
I installed the **Xfce** desktop environment; on Debian 10 this is bundled with the **[[https://packages.debian.org/buster/network-manager|NetworkManager]]** service, which handles wired and wireless connections.
Beware that NetworkManager does conflict with the **/etc/wpa_supplicant/wpa_supplicant.conf** configuration file: if you configure a WiFi connection in this file, you will end-up with two **wpa_supplicant** instances conflicting each other (so you shouldn't even use the trick to [[https://www.raspberrypi.org/documentation/configuration/wireless/headless.md|setup a Raspberry Pi headless]]). Use instead the NetworkManager applet from the Xfce environment to connect to your WiFi network, the network preferences will be saved into **/etc/NetworkManager/system-connections/**.
==== Desktop Autologin ====
We want the Raspberry Pi to start automatically a graphic session, so in **raspi-config** we selected **Boot Options** => **Desktop / CLI** => **Desktop Autologin**. The logged-in user will be **pi**.
==== Syslog ====
To limit the useage of the SD card, we prefer to generate system logs in RAM instead of writing them to filesystem. So we installed the **busybox-syslogd** packages, which removes the **rsyslog** one. Once installed, you can see system log using the **logread** command.
==== GL Warning ====
Running the **photo-reframe** application on the Raspberry Pi will show a warning message:
libEGL warning: DRI2: failed to authenticate
It turned out that we have to set the //GL Driver// to avoid that warning. Once launched **raspi-config**, select **Advanced Options** => **GL Driver** (this choiche will install the **gldriver-test** package) => **GL (Fake KMS)**.
Actually we used a fake workaround, because activating the **Full KMS** option causes several crashes of the graphical system, the errors logger are something like:
[drm:drm_atomic_helper_wait_for_dependencies [drm_kms_helper]]
*ERROR* [PLANE:183:plane-21] flip_done timed out
[drm:drm_atomic_helper_wait_for_flip_done [drm_kms_helper]]
*ERROR* [CRTC:74:crtc-2] flip_done timed out
[drm:drm_atomic_helper_wait_for_dependencies [drm_kms_helper]]
*ERROR* [CRTC:74:crtc-2] flip_done timed out
[drm:drm_atomic_helper_wait_for_dependencies [drm_kms_helper]]
*ERROR* [CONNECTOR:32:HDMI-A-1] flip_done timed out
==== Hide the mouse pointer ====
If you use only the keyboard to control the interface, the **mouse pointer** at the center of the screen is definitely annoying. Fortunately enough there is the Debian package **unclutter**: once installed you will find a running process when you initiate your desktop session:
/usr/bin/unclutter -idle 1 -root
The mouse pointer will disappear after one second of **idle time**, just to reappear if you move the mouse. If you want to customize the options, change the file **/etc/default/unclutter**.
==== Turning off the power LED ====
When the digital frame is in stand-by (the screen is black and turned off), there is a red light glow around the frame, caused by the **Raspberry Pi power LED** being very bright, this is particularly disturbing when the room is dark. Fortunately enough there is a way to turn off the LEDs, just add the following snippet at the end of **/boot/config.txt** and reboot:
# Disable Ethernet LEDs
dtparam=eth_led0=14
dtparam=eth_led1=14
# Disable the PWR LED
dtparam=pwr_led_trigger=none
dtparam=pwr_led_activelow=off
# Disable the Activity LED
dtparam=act_led_trigger=none
dtparam=act_led_activelow=off
This works well on my **Raspberry Pi 2** model, the matter is discussed in a **[[https://www.raspberrypi.org/forums/viewtopic.php?t=149126|post of the RaspberryPi.org forum]]**.
==== Keyboard Shortcut ====
We choosed XFCE as Desktop Environment, so we can use //Settings// => //Keyboard// => **Application Shortcuts** to associate a key combination to an action. We decided to associate **Ctrl-Q** with the applet **xfce4-session-logout**. The setting is saved into **$HOME/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-keyboard-shortcuts.xml**.
==== Screen Saver ====
The program **photo-reframe** is configured to call two external programs, one to **disable the screensaver** (at program start) and one to **re-enable the screensaver** (at program exit). The two helper programs should be named **screensaver-off** and **screensaver-on** respectively, and they are searched into the **PATH**. In this way you can leave the desktop power saving active: the screen will remain active if a slideshow is running, but it goes blank otherwise.
Beware that the **xfce4-power-manager** program overloads the functionality offered by DPMS (controlled by the **xset** program); e.g. the screen blanking is perfomed even with DPMS disabled. The reccommended XFCE power manager settings (//Settings// => //Power Manager// => //Display//) are:
* **Display power management**: On - This will **enable DPMS**.
* **Blank after**: Never - This prevents the software screen blanking (no DPMS).
* **Put sleep after**: 5 minutes - This is enforced via **DPMS Standby**.
* **Switch off after**: 6 minutes - This is enforced via **DPMS Off**.
With these settings display blanking is controlled by DPMS only (no software blanking); the slideshow program can simply disable DPMS to keep the screen always on. XFCE saves the Power Manager settings into the file **$HOME/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml**.
=== screensaver-off ===
#!/bin/sh
# Disable software screen saver.
xset s off
# Disable DPMS screen saver.
xset dpms force on
xset -dpms
=== screensaver-on ===
#!/bin/sh
# Disable software screen saver.
xset s off
# Enable DPMS screen saver.
xset dpms 300 300 300
xset +dpms
=== How to use xset ===
With the command **xset q** it is possibile to query the status of the **[[wp>VESA_Display_Power_Management_Signaling|DPMS]]** (you must be the user owning the X display):
xset q
...
DPMS (Energy Star):
Standby: 600 Suspend: 600 Off: 600
DPMS is Enabled
Monitor is On
On the Raspberry Pi, the auto-logon user is **pi**, if you are root you can set the **DISPLAY** and **XAUTHORITY** environment variables before calling xset. Check the running **Xorg** process to get such variables:
ps -C Xorg ho args
/usr/lib/xorg/Xorg :0 -seat seat0 -auth /var/run/lightdm/root/:0 -nolisten tcp vt7 -novtswitch
Now you can execute **xset** as user **root**:
export DISPLAY=":0" XAUTHORITY="/var/run/lightdm/root/:0"; xset q
If you disable the screensaver from the desktop environment (in our case XFCE //Settings// => //Power Manager// => //Display//), you will see the line **DPMS is Disabled** in ''xset q'' output.
==== Desktop Fonts ====
To have bigger fonts into XFCE menu we opened the **Settings** => **Appearance** => **Fonts** menu and increased the font size. Settings are saved into the file **$HOME/.config/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml**.
===== Executing programs from the Firefox browser =====
Our digital frame will use a web page as the main user interface; the browser will start automatically at boot time and it will connect to a page located on **%%http://localhost/%%**. A local running Apache+PHP will serve the page showing thumbnails for image folders.
Basically from the web page we want to be able to execute two actions:
* The slideshow program **photo-reframe** to actually view the slideshow.
* Shell scripts using the **bash** shell, to do actions like shutdown, reboot, etc.
FIXME To be completed...
===== Firefox customization =====
**RaspiOS 2020-05-27 Buster** (based on Debian 10.4) installaed **Firefox Version 68.12.0esr**.
==== Disable the session restore page ====
If Firefox is badly closed (e.g. due a power outage, etc.), when it starts again it display the page **about:sessionrestore**. To disable this behaviour open the **about:config** and set:
browser.sessionstore.resume_from_crash => false
==== Disable the status panel ====
Firefox shows a status bar in the lower left corner of the window, where it shows the URL currently focused or under the mouse. To disable this feature open the **about:config** page and set:
toolkit.legacyUserProfileCustomizations.stylesheets => True
then create a file **$HOME/.mozilla/firefox/.default-esr/chrome/userChrome.css** with this content:
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
#statuspanel { display: none !important; }
See this [[https://support.mozilla.org/en-US/questions/1285060|support page]].
==== Starting in fullscreen mode ====
We choosed the **[[https://github.com/tazeat/AutoFullscreen|AutoFullscreen]]** extension, by **tazeat**. Open the Firefox Menu => Addons => Extensions and search for it. Once installaed, it is saved into the directory **$HOME/.mozilla/firefox/.default-esr/extensions/{}.xpi**.
With that extension loaded, Firefox will start in fullscreen automatically. Press **F11** as usual to toggle this state.
===== Programs Autostart =====
We want to run automatically two processes at startup
* The **Firefox** browser, pointing to **%%http://localhost/%%**. This is the main user interface, used to browse image folders and to start the slideshow.
* The **photo-reframe** program to show images from a randomly generated playlist. This is the slideshow started automatically at startup.
We achieve this creating two **.desktop** files into the **.config/autostart** directory of the **pi** user.
This is the **/home/pi/.config/autostart/firefox-esr.desktop** file:
[Desktop Entry]
Name=Firefox ESR
Comment=Browse the World Wide Web
GenericName=Web Browser
X-GNOME-FullName=Firefox ESR Web Browser
Exec=/usr/lib/firefox-esr/firefox-esr http://localhost/
Terminal=false
X-MultipleArgs=false
Type=Application
Icon=firefox-esr
Categories=Network;WebBrowser;
StartupWMClass=Firefox-esr
StartupNotify=false
Path=
This is the **/home/pi/.config/autostart/play-playlists.desktop** file:
[Desktop Entry]
Type=Application
Version=1.0
Name=Play-Playlists
Icon=image
TryExec=/home/pi/Scripts/play-playlists.sh
Exec=/home/pi/Scripts/play-playlists.sh --delay 16
Terminal=false
===== Fixed WiFi MAC address =====
Everytime the Raspberry Pi is rebooted, it gets a new MAC address for the **wlan0** interface. This is a //feature// provided by the **Network Manager** package.
If you want to disable this behaviour, create a new file **/etc/NetworkManager/conf.d/100-disable-wifi-mac-randomization.conf** whith this content:
[connection]
wifi.cloned-mac-address=1
[device]
wifi.scan-rand-mac-address=no
See the man page for **nm-system-settings.conf**, the article **[[https://fedoramagazine.org/randomize-mac-address-nm/|Randomize your MAC address using NetworkManager]]** and this **[[https://www.raspberrypi.org/forums/viewtopic.php?f=63&t=196348&start=25#p1524581|post]]** on how to disable it on the Raspberry Pi.
Alternatively you can uninstall the **NetworkManager** package and use **dhcpcd5** for all the network settings.
===== Web References =====
* **[[https://www.raspberrypi.org/documentation/configuration/config-txt/video.md|Video options in config.txt]]**
* **[[https://wiki.archlinux.org/index.php/Xfce#Display_blanking|XFCE, DPMS and display blanking]]**