seast
Posts: 7
Joined: Wed Jan 23, 2013 5:10 pm

Motion sensitive photo frames

Wed Jan 23, 2013 9:53 pm

A while back I built some photo frames using old 18" LCD monitors and recently I decided to use Pis to drive these screens - you can find more info on how the screens look here - but I thought it might be useful to others to document how I did this.

Image

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
and changing the name raspberrypi to something else - in my case I named my devices frame-landscape01 and 02, frame-portrait01 and 02 and motion-detect.

You then need to edit /etc/hostname and change the name there too:

Code: Select all

sudo nano /etc/hostname
Then download the Bonjour client and reboot:

Code: Select all

sudo apt-get update
sudo apt-get install libnss-mdns
sudo reboot
So assuming you called your Pi frame-landscape01 you can now ping and ssh frame-ladscape01.local from a Mac or other Pi with Bonjour running (or I guess a Windows machine with Bonjour installed by iTunes).

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
Then create a file in the home directory called slideshow containing:

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
and a file called cron containing the crontab settings to run a script once a week:

Code: Select all

0 4 * * 0  /home/pi/get_photos
and a file called get_photos that is that script that gets run:

Code: Select all

#!/bin/bash

orient=landscape
#orient=portrait
number=01

mount_afp afp://username:[email protected]/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
You will need to edit this script to change the ladscape/portrait and frame number and you'll need to put in the appropriate username/password/server details too. There are a few sleeps in this script to give the server time to come out of powersave - you may need to adjust for your set-up. Replacing the photos will cause the qiv viewer to stop - so seemed like the easiest thign was to just reboot the whole system once a new set of photos have been downloaded.

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
And one called screen_off containing:

Code: Select all

/opt/vc/bin/tvservice -o
Then make these various scripts executable:

Code: Select all

chmod +x slideshow
chmod +x screen_on
chmod +x screen_off
chmod +x get_photos
Make the pi auto-login by editing /etc/inittab using

Code: Select all

sudo nano /etc/inittab
Find the line that says

Code: Select all

1:2345:respawn:/sbin/getty 115200 tty1
Comment it out by putting a # at the start and add below a new line:

Code: Select all

1:2345:respawn:/bin/login -f pi tty1 </dev/tty1 >/dev/tty1 2>&1
Create a file to auto start LXDE in the home directory called .bash_profile containing:

Code: Select all

if [ -z "$DISPLAY" ] && [ $(tty) = /dev/tty1 ]; then
  startx
fi
And finally create a file to make LXDE start the slideshow called .xinitrc containing:

Code: Select all

/home/pi/slideshow
With all this in place the Pi will auto login, start up the image viewer and display the contents of the photos directory - and once a week will download a new set of photos from the server.

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
And this called the process script:

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
The purpose of the process script is to randomly choose up to 2020 photos for a given frame - 2020 being the amount you need for a week's worth of photos if they change every 5 mins.

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

Image

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 [email protected]$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 [email protected]$frame /home/pi/screen_off &
      done
      screens_on=0
      start_time=`date +%s`
  fi
done
This script looks for changes on GPIO 23. If there is no movement for 10 mins it turns the screens off by ssh ing into each frame in turn and running the screen_off script. Likewise if movement is detected then the screen_on script gets run.

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
You need to create a file called frame_list containing the names of the frames - in my case:

Code: Select all

frame-landscape01.local
frame-landscape01.local
frame-portrait01.local
frame-portrait02.local
You will want to make the frame auto login as per instructions above but this time the .bash_profile file needs to just contain:

Code: Select all

if [ -z "$DISPLAY" ] && [ $(tty) = /dev/tty1 ]; then
  /home/pi/detect
fi

Ottoman
Posts: 9
Joined: Fri Jan 25, 2013 3:23 am

Re: Motion sensitive photo frames

Wed Jan 30, 2013 7:34 pm

Thanks for posting. I want to do a similar project like this. How did you connect the screens to the Pi? Via HDMI? I have some LCD display's from old laptops which I wanted to make into digital photo frames, but I don't think there is any kind of adapter to connect the ribbon cable off the LCD to the Pi.

sportsnapper
Posts: 69
Joined: Wed Sep 05, 2012 11:27 am

Re: Motion sensitive photo frames

Thu Jan 31, 2013 10:48 pm

Great project....

I was thinking that 5xPi's is an expensive investment - but then looking at the proice of some 'normal' frames, it's not really that bad.

Ottoman, I'm presuming it uses an HDMI-DVi lead - put there's ots of connectivity options. My problem (even as photographer) would be providing enough sets of images to be changed each week...

swendl
Posts: 3
Joined: Mon Feb 04, 2013 4:23 am

Re: Motion sensitive photo frames

Mon Feb 04, 2013 4:26 am

Hi - did you use laptop LCDs or desktop monitor units? If the latter I'd be interested in seeing how you arranged and connected things in such a relatively thin package. Do you have this information posted somewhere?

mhct
Posts: 5
Joined: Mon Feb 11, 2013 7:47 am

Re: Motion sensitive photo frames

Mon Feb 11, 2013 7:54 am

Great work seast, thanks for sharing.

I wonder how you hided the power cables of your Rpi?
Did you add place power sockets on the walls?
A different topic is, which kind of buffer could you use to protect the Rpi from over voltage?

thanks

Schuitz
Posts: 15
Joined: Sun Jan 27, 2013 1:17 pm

Re: Motion sensitive photo frames

Thu Mar 28, 2013 9:07 pm

Brilliant! It seems so many of us are trying to put frames together, sooner or later we are going to have to band together to make a truly awesome app that has some custom capabilities beyond qiv and fbi.

I have mounted an LCD similarly, but also have all the parts in hand to make a simple arduino-based gesture controller to swipe next/previous photo etc. I had thought of using PIR to make it "people-aware" and now you have me convinced to try.

My screen is mounted in the classic way, behind a mat and glass. On properly sized images (in the day) you can not even tell that it isn't a paper print.

Schuitz
Posts: 15
Joined: Sun Jan 27, 2013 1:17 pm

Re: Motion sensitive photo frames

Thu Mar 28, 2013 9:22 pm

Also, I am curious about the rationale behind using a fifth Pi to run the motion sensing. Why not just run a long 3-wire and do the task on one of the four Pis?

mow
Posts: 1
Joined: Fri Jun 14, 2013 4:11 pm

Re: Motion sensitive photo frames

Fri Jun 14, 2013 4:20 pm

What PIR sensor did you use?
Most of them I find operate on 12V and not 3.3V. Or did you solve it in some other way?
How do you wire from PIR to raspberry?

nicoco59
Posts: 2
Joined: Fri Aug 08, 2014 11:57 am

Re: Motion sensitive photo frames

Fri Aug 08, 2014 11:58 am

Hi,

I have the same question as mow. What Pie did you use and how did you wire it with your Pi ?

Thanks for your help.

Nicolas.

PepsiZilla
Posts: 1
Joined: Tue Feb 21, 2017 6:38 pm

Re: Motion sensitive photo frames

Tue Feb 21, 2017 6:48 pm

I am looking for more ideas like this. I what to mount 4 or 5 monitors and have them all display different photos. You created this in 2013 any updates? improvements?
Thanks

User avatar
DougieLawson
Posts: 34568
Joined: Sun Jun 16, 2013 11:19 pm
Location: Basingstoke, UK
Contact: Website Twitter

Re: Motion sensitive photo frames

Wed Feb 22, 2017 7:03 pm

The OP hasn't visited the forum in a long while.

Try http://piwall.co.uk/
Note: Having anything remotely humorous in your signature is completely banned on this forum.

Any DMs sent on Twitter will be answered next month.

This is a hippy & doctor free zone.

Return to “Other projects”