
As you can see above I have two frames of each orientation displaying photos with a Pi driving each one - and there is a fifth Pi connected to a PIR detector that puts the screens into power save if there has been no movement around them for a while. Photos are downloaded to the frames from a Mac server once a week - if your server is not a Mac then it should be easy enough to adapt these scripts for connecting to other systems.
Naming The Pi
Because we have several Pis running and we need to be able to connect to them from the motion detecting Pi I decided using Bonjour to provide local name resolution would make things easier. So firstly you need to edit the name of the Pi by doing
Code: Select all
sudo nano /etc/hosts
You then need to edit /etc/hostname and change the name there too:
Code: Select all
sudo nano /etc/hostname
Code: Select all
sudo apt-get update
sudo apt-get install libnss-mdns
sudo reboot
The Frames
The frame set-up is based on this qiv post by NerdUno but adds a script to download a new set of photos from a server once a week. To set it up:
Code: Select all
sudo apt-get install qiv
sudo apt-get install afpfs-ng
sudo apt-get install x11-xserver-utils
mkdir photos_mount
mkdir photos
sudo usermod -a -G fuse pi
sudo reboot
Code: Select all
crontab cron
crontab -l
./screen_on
xset s off
xset -dpms
xset s noblank
qiv --slide --random --delay 300 --no_statusbar --autorotate --maxpect photos
Code: Select all
0 4 * * 0 /home/pi/get_photos
Code: Select all
#!/bin/bash
orient=landscape
#orient=portrait
number=01
mount_afp afp://username:password@server.local/Photos photos_mount
sleep 10
ls photos_mount/PhotoFrames/$orient$number/1.jpg
sleep 20
if [ -f photos_mount/PhotoFrames/$orient$number/1.jpg ]
then
rm photos/*.jpg
cp photos_mount/PhotoFrames/$orient$number/*.jpg photos
sleep 10
else
echo "No photos found..."
fi
afp_client unmount photos_mount
sudo reboot
Create a script to turn the screen on called screen_on containing:
Code: Select all
/opt/vc/bin/tvservice -p
sudo chvt 6
sudo chvt 7
Code: Select all
/opt/vc/bin/tvservice -o
Code: Select all
chmod +x slideshow
chmod +x screen_on
chmod +x screen_off
chmod +x get_photos
Code: Select all
sudo nano /etc/inittab
Code: Select all
1:2345:respawn:/sbin/getty 115200 tty1
Code: Select all
1:2345:respawn:/bin/login -f pi tty1 </dev/tty1 >/dev/tty1 2>&1
Code: Select all
if [ -z "$DISPLAY" ] && [ $(tty) = /dev/tty1 ]; then
startx
fi
Code: Select all
/home/pi/slideshow
On The Server
The server needs to run a script once a week to prepare a set of photos to be downloaded to the frames. As well as sorting them into portrait and landscape it resizes them to the display size - in my case 1280x1024. Any photos tagged with ExcludeFromPhotoFrame are ignored. You need to have ImageMagik installed on your machine in order to run this script:
Code: Select all
#!/bin/bash
find ../Public -type f -name *.jpg >file_list
rm *.list
landscape=1
portrait=1
cat file_list | while read f; do
res=`identify -format "%[fx:w] %[fx:h] %[exif:orientation] %[IPTC:2:25]" "$f"`
resarray=( $res )
width=${resarray[0]}
height=${resarray[1]}
orientation=${resarray[2]}
keywords=${resarray[3]}
if [ "$keywords" == ExcludeFromPhotoFrame ]
then
echo "Excluding $f"
echo $f >>excluded.list
else
if (( orientation >= 5 ))
then
tmp="$height"
height="$width"
width="$tmp"
fi
if [ $height -ge $width ]
then
if [ $height -ge 1000 ]
then
echo "Portrait: $f $width $height"
echo $f >>portrait0$portrait.list
portrait=$(( portrait+1 ))
if ((portrait == 3))
then
portrait=1
fi
fi
else
if [ $width -ge 1000 ]
then
echo "Landscape: $f $width $height"
echo $f >>landscape0$landscape.list
landscape=$((landscape+1))
if (( landscape == 3 ))
then
landscape=1
fi
fi
fi
fi
done
./process landscape 01
./process landscape 02
./process portrait 01
./process portrait 02
Code: Select all
#!/bin/bash
rm $1$2/*.jpg
count=`wc -l $1$2.list | sed -e 's/^ *//g;s/ *$//g' | cut -f1 -d' '`
echo "Total of $count files listed"
filename=1
cat $1$2.list | while read f; do
let "use_photo = $RANDOM % $count"
if (( use_photo <= 2020 ))
then
echo "Converting $f"
echo $f >>using_$1$2.list
if [ "$1" == landscape ]
then
convert "$f" -auto-orient -resize 1280x1024^ -gravity center -extent 1280x1024 $1$2/$filename.jpg
else
convert "$f" -auto-orient -resize 1024x1280^ -gravity center -extent 1024X1280 -rotate 90 $1$2/$filename.jpg
fi
filename=$((filename+1))
if (( filename > 2020 ))
then
break
fi
fi
done
These scripts end up producing a set of jpg files numbered 1.jpg, 2.jpg etc in sub-folders called landscape01, landscape02, portrtait01 etc which is where the frame download script goes to find them.
You'll need to adapt these scripts to you server setup depending where you have photos stored etc - but this should give you a starting point.
Motion Detecting Pi

The final Pi can then be set up and named something as per the instructions above - I call mine motion-detect.
To connect the Pi to the PIR detector you will need to connect a two core wire to the PIR relay at one end and a GPIO pin (I used GPIO 23) and ground on the Pi side. The PIR relay will be normally closed so this will ground GPIO 23, but when it opens if the GPIO is set to pull-up mode the pin will go high. For more on GPIO connections have a look here.
If you don't have much experience of connecting to GPIO pins note that they connect directly to the main chip - so connecting the wrong voltage like 5V to the wrong pin can blow the chip up - so you might want to use an external buffer adaptor that will protect you from causing harm to your Pi.
To detect changes in the GPIO pin I am using a simple bash script - so firstly you'll need to install the shell GPIO tools following the instructions here.
The create a script called detect in the home directory containing:
Code: Select all
#!/bin/bash
gpio -g mode 23 in
gpio -g mode 23 up
start_time=`date +%s`
screens_on=0
while true; do
if [ `gpio -g read 23` == 1 ]
then
if (( screens_on == 0 ))
then
cat frame_list | while read frame
do
echo "Switching $frame on..."
sshpass -p raspberry ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no pi@$frame /home/pi/screen_on &
done
screens_on=1
fi
start_time=`date +%s`
fi
sleep 0.8
now=`date +%s`
if (( now - start_time >= 600 ))
then
cat frame_list | while read frame
do
echo "Switching $frame off..."
sshpass -p raspberry ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no pi@$frame /home/pi/screen_off &
done
screens_on=0
start_time=`date +%s`
fi
done
IMPORTANT: The script uses sshpass to provide the ssh password automatically and shh has options applied so that warnings about secure connections are ignored. Normally this would be highly questionable security practice - but I'm assuming here the frames are on a private network and thus security is not a big issue. If that is not the case then you'd need to use proper ssh password handing methods instead.
You need to make detect executable
Code: Select all
chmod +x detect
Code: Select all
frame-landscape01.local
frame-landscape01.local
frame-portrait01.local
frame-portrait02.local
Code: Select all
if [ -z "$DISPLAY" ] && [ $(tty) = /dev/tty1 ]; then
/home/pi/detect
fi