The La Darsena Webcam Project

After we came to the decision to install a webcam at Hotel La Darsena, we tried to find a webcam with a high picture quality to honor the great view we have at Lake Como. But when it comes to night shots, even the more expensive webcams deliver just a very poor quality. But what to do, if there is no appropriate webcam available for an affordable price? In short: we build our own webcam with a Canon EOS 1200D, a Raspberry Pi, and a (unused) drain pipe as housing. Below a “making-of” for anyone interested in technical details. If you need further informations, please send an email to admin@ladarsena.it


Table of contents

Hardware

Canon EOS 1200D

Canon EOS 1200D

The 1200D with the EF-S 18-55mm III kit has Canon EOS quality at an unbeatable price and meets all our requirements, like high resolution (5184×3456), long exposure time (30s), and USB connectivity. The battery has to be exchanged with a coupler, connected with a 7.4V power supply. Very handy is a short USB cable with an angled Micro USB plug. Oh, and we need a SD card.

Canon EOS 1200D Kit Canon EOS 1200D with EF-S 18-55mm III kit amazon.it 330,00 EUR
AC DR-E10 fake battery coupler ACK-E10 power supply 7.4V 2000mA, AC DR-E10 fake battery coupler
A replacement for the battery, to have continous current.
amazon.de 19,00 EUR
SD Card 8GB SD card 8GB, Class 10
Any SD card is fine, 8GB is enough since no images are stored in the camera. Size doesn’t matter, speed does.
amazon.de 9,00 EUR
USB cable USB-A to Micro-USB angle plug, 50cm USB cable USB-A to Micro-USB angle plug, 50cm
Space-saving cable, with 90° bent Micro-USB plug towards the back of the camera.
partsdata.de 6,00 EUR

Raspberry Pi 2

Canon EOS 1200D A Raspberry Pi is a single-board computer with the size of a credit card. Originally developed to teach children in computer science, it became a great success all over the world – not just for kiddies. Different models are avalaible, the Raspberry Pi 2B is 2nd generation. Fast and neat. Different operating systems are available for free.
Raspberry Pi 2 Mod B Raspberry Pi 2B reichelt.de 36,00 EUR
Power supply 5V, 2000mA, Micro-USB Power supply 5V, 2000mA, Micro-USB reichelt.de 23,00 EUR
EDIMAX EW-7811UN WiFi 802.11b/g/n nano USB Adapter, 150 MBit/s EDIMAX EW-7811UN WiFi 802.11b/g/n nano USB Adapter, 150 MBit/s
Note: It’s highly recommended to use a LAN connection, WiFi is not as stable as LAN
reichelt.de 7,00 EUR
MicroSD card 16GB, Class 10 MicroSD card 16GB, Class 10
Any size is fine, even 4GB are enough. Size doesn’t matter, speed does.
As bigger the memory is, as more images can be buffered while offline.
amazon.de 9,00 EUR

Housing

Do-it-yourself housing

drain pipe as webcam housing As a housing we used a standard orange drain pipe from a local builder’s merchant. PVC is easy to work with, light weighted and resistant. The viewing glass we got from a local glazier’s workshop. The plate to mount the camera and all other parts and the self-designed gimbal mounting kit we got from a local metalworker.
Drain pipe DN160 Ø160mm with end cover Drain pipe DN160 Ø160mm with end cover local hardware store 10,00 EUR
Mounting plate Mounting plate in stainless steel to carry all parts local metalworker 8,00 EUR
Gimbal mounting kit Gimbal mounting kit in stainless steel local metalworker 15,00 EUR
clamps Ø160mm 2 clamps Ø160mm stainless steel
To attach the pipe to the gimbalk mounting kit.
ebay.de 22,00 EUR
Viewing glass Viewing glass, fitting the pipe. Fixed with some silicon local glazier 3,00 EUR

Useful parts for housing

Seeed Studio Raspberry Pi Relay Board v1.0 Seeed Studio Raspberry Pi Relay Board v1.0
Expansion board with 4 relays for the Raspi.
Perfect to power-off/on (reset) the camera and to switch fans.
exp-tech.de 29,00 EUR
Fan 5V 40x40mm Fan 5V 40x40mm
used as a cooler fan
reichelt.de 2,00 EUR
Fan 5V 20x20mm Fan 5V 20x20mm
used as a antifog fan to keep the viewing glass clear
reichelt.de 5,00 EUR
Cable USB-A to USB-A, 1m Cable USB-A to USB-A, 1m
Cut the cable in 2 pieces to connect both fans with USB power
reichelt.de 1,00 EUR
RPI mounting kit 20mm RPI mounting kit 20mm reichelt.de 4,00 EUR
Screw 1/4" to attach the camera Screw 1/4" to attach the camera amazon.de 2,00 EUR

Software Camera Server

Raspbian Jessie

There are quite a few operating systems available for the Raspberry Pi, meanwhile even Windows 10. We are using the original: Raspbian Jessie, based on Debian Linux OS. Linux is a very stable OS and it’s Open Source. To capture images with the camera we use gphoto2. The following description is not really for Linux beginners, you should be somehow familiar with Linux. A complete installation of Raspbian Jessie is presumed. All scripts are running as user root. If you are not root, the scripts has to be changed accordingly. Further it is presumed that you have SSH access to a web server and the Raspi root’s rsa-key is in authorized_keys of the web server. For maintenance of the webcam, we’ve set up an OpenVPN connection with the web server, so we can manage the webcam thru NATs and firewalls, no matter what IP it has and in which network.

Camera Settings

In Canon EOS 1200D menu we have to set some parameters:
# Wheel knob:
Modus P

# Lense:
Autofocus ON

# Menu settings:
Menu 1: Quality:         M normal
        Beep:            Disable
        Image review:    Off
        Red eye reduct:  Disable
        Flash control:   Disable Flash firing
Menu 3: ISO Auto         Max: 800
Menu 4: Live View Shot:  Enable
        AF Mode:         Live Mode
Menu 7: Auto power off:  Off		
Menu 8: LCD brightness:  As dark as possible
Menu 9: Custom Functions M1: 0 
                         M2: 0
                         M3: 2 On, Long exp. noise reduction

Install the required packages

apt-get update
apt-get upgrade
apt-get install imagemagick     # image manipulation
apt-get install exiftool        # read/write exif data
apt-get install rsync           # to upload images to server
apt-get install syslog-ng       # we want a nice syslog
The gphoto2 package of Raspbian is outdated and gphoto2 has to be build from sources. You can do this by yourself from Github or you use the handy gphoto2-updater.

Directory tree

/root
     /images                       # temporary directory for images
     /outbox                       # files in outbox are being sent to webserver
     eos-capture.sh                # the main program
     eos-checkimage.sh             # check the focus after captured
     eos-focusreset.sh             # rest the focus manually
     eos-upload-all.sh             # upload all old images in /root/outbox
     eos-upload-latest.sh          # upload latest image in /root/outbox
	 
/etc/systemd/system/
     eos-capture.timer             # a systemd timer is much better than cron jobs
     eos-capture.service           # starts /root/eos-capture.sh
     eos-upload-all.service        # starts /root/eos-upload-all.sh
     eos-upload-latest.service     # starts /root/eos-upload-latest.sh

Scripts on Raspberry Pi

/root/eos-capture.sh
#!/bin/bash
#
# /root/eos-capture.sh
# Capture images from a Canon EOS 1200D

cd /root/images || exit 1

NOW=$(date +"%Y%m%d-%H%M") 
FILENAME="webcam_$NOW.jpg"
SERVERTARGET="your.webserver.tld:/yourpathtodirectory/webcam/inbox"
# iso: 0= auto, 1=ISO 100, 2=ISO 200, 3=ISO 400, 4=ISO 800
# Best is ISO auto and limit ISO to 800 in camera menu
ISO="0"
# imageformat: 0=Large-Fine, 1=Large-Normal, 2=Medium-Fine, 3=Medium-Normal
RESOLUTION=3

# capture image
# eosremoterelease=5 takes the picture immediately, without autofocussing
gphoto2 --force-overwrite --set-config imageformat=$RESOLUTION \
        --set-config iso=$ISO --set-config eosremoterelease=Immediate \
        --wait-event-and-download=40s --set-config eosremoterelease=4 \
        --filename $FILENAME >/dev/null

# if the image has been downloaded successfuly
if [ -f $FILENAME ]; then
    echo "$FILENAME captured successfully. Checking focus..."
    /root/eos-checkimage.sh $FILENAME
    # crop image to 16:9, keep resolution
    mogrify -crop 3456x1944+0+0 $FILENAME 
    # OK, now we can move the image into the outbox
    mv $FILENAME /root/outbox

# no image downloaded, something must be wrong	
else
    echo "error: Image $FILENAME not downloaded!"
    # log to system.log
    logger -p syslog.error -t [insert_php]include("webcam-project.inc");[/insert_php][$$] $FILENAME not downloaded, resetting camera
    # here you should reset the camera by switching of power for 1 second
fi
/root/eos-checkimage.sh
#!/bin/bash
#
# /root/eos-checkimage.sh
# Check the focus of the image and the temperature of the camera
#
cd /root/images || exit 1

if [ "" ]; then
  FILENAME=
else
  FILENAME=$(ls -1t | head -1)
fi

#echo "Checking image exif data of $FILENAME"
FOCUSDATA=$(exiftool -a -u -g1 $FILENAME | egrep 'Focus Distance|Camera Temp' \
          | sed 's/Focus Distance //g' | sed 's/Camera //g' \
          | tr '\n' ' ' | sed 's/  //g' )

IFS=' ' read -ra FIELD <<< "$FOCUSDATA"

TEMPERATURE=${FIELD[1]}
FOCUS=${FIELD[4]}

# if field 4 is "inf" then there is one field less to determine FOCUS2
if [ ${FIELD[4]} = "inf" ]; then
   FOCUS2=${FIELD[6]}
else
   FOCUS2=${FIELD[7]}
fi

# lower focus should be either 5.27
if [ "$FOCUS2" != "5.27" ]; then
  echo "Image out of focus. Performing focus reset (Lower: $FOCUS2)"
  FOCUSMSG="focus reset!"
  /root/eos-focusreset.sh
fi

# Oh yes, the EOS has a temperature sensor, perfect to switch on the cooler fan
if [ "$TEMPERATURE" -gt 42 ]; then
  echo "Cooler fan ON ($TEMPERATURE C)"
  # switch on your cooler fan here
else
  echo "Cooler fan OFF ($TEMPERATURE C)"
  # switch off your cooler fan here
fi

# log to system.log
logger -p local0.info -t eos-checkimage.sh[$$] "$FILENAME focus: $FOCUS/$FOCUS2 \
       camera: $TEMPERATURE°C ($TEMPERATUREMSG) $FOCUSMSG"
/root/eos-focusreset.sh
#!/bin/bash
#
# /root/eos-focusreset.sh
# Reset the focus manually. Autofocus often fails, especially in the night
#
# Choice: 0 Near 1
# Choice: 1 Near 2
# Choice: 2 Near 3
# Choice: 3 None
# Choice: 4 Far 1
# Choice: 5 Far 2
# Choice: 6 Far 3
#
# focus reset 1x6 4x1 4x4
# and
# focus reset 1x6 3x1 0x0
# are identical	

# the best manual focus setup for landscape
echo "focus reset 1x6 3x1 0x0"
gphoto2 --quiet --set-config evfmode=1 \
    --set-config viewfinder=1 --wait-event=1s \
    --set-config manualfocusdrive=6 --wait-event=1s \
    --set-config manualfocusdrive=1 --wait-event=1s \
    --set-config manualfocusdrive=1 --wait-event=1s \
    --set-config manualfocusdrive=1 --wait-event=1s \
    >/dev/null
/root/eos-upload-all.sh
#!/bin/bash
#
# /root/eos-upload-all.sh
# upload all abandoned images in outbox, in case we were offline

SERVERTARGET="your.webserver.tld:/yourpathtodirectory/webcam/inbox"

cd /root/outbox || exit 1

# uploading old images is not that important, so limit bandwith to minimum
rsync -Pazq --bwlimit=25 --remove-source-files . $SERVERTARGET
/root/eos-upload-all.sh
#!/bin/bash
#
# /root/eos-upload-all.sh
# upload latest image, it has priority before any old images

SERVERTARGET="your.webserver.tld:/yourpathtodirectory/webcam/inbox"

cd /root/outbox || exit 1

LATEST=$(ls -1t | head -1)
rsync -Pazq --bwlimit=60 --remove-source-files $LATEST $SERVERTARGET

systemd files on Raspberry Pi

Back in the days we had to start timed scripts with a cron job. Nowadays we have systemd, which handles timed scripts and dependend scripts in a smarter way. The timer starts automatically after boot and starts exactly every full minute eos-capture.sh. After a succesfull capture, the latest image will be uploaded in the background while the camera is already available for next shot. If any process fails, systemd takes care of it and restarts it. Very neat tool.

/etc/systemd/system/eos-capture.timer
[Unit]
Description=Take a photo every minute

[Timer]
OnCalendar=*:*:00
AccuracySec=100ms

[Install]
WantedBy=multi-user.target
/etc/systemd/system/eos-capture.service
[Unit]
Description=Take a photo with the EOS camera
Wants=eos-upload-latest.service
Before=eos-upload-latest.service

[Service]
Type=oneshot
ExecStart=/root/eos-capture.sh
/etc/systemd/system/eos-upload-latest.service
[Unit]
Description=Upload the latest image
Wants=eos-upload-all.service
Before=eos-upload-all.service

[Service]
Type=oneshot
ExecStart=/root/eos-upload-latest.sh
/etc/systemd/system/eos-upload-all.service
[Unit]
Description=Upload all images

[Service]
Type=oneshot
ExecStart=/root/eos-upload-all.sh

Web server side scripts

So once the images arrived in web servers inbox, we have to process them. The proccessing script is also controlled by systemd. With an old fashioned cronjob we launch a script to create a time lapse movie out of our 1440 daily images, 5 minutes after midnight.

Directory tree

/inbox                # the directory where the Raspi uploads the images
/logo                 # our logo
/tmp                  # temp dir for creatiung the time lapse movie
/img                   
    /hd               # the final hd 1920x1080 images
    /hires            # high resulution images
    /thb              # thumbnails
    /org              # the archive of the original image without label
    /movie            # the time lapse movies
image-processor.sh 	  # waits for arriving images an processes them
maketimelapse.sh      # script to create the time lapse movie

Scripts

image-processor.sh
#!/bin/bash
#
# image-processor.sh
# process incoming images and add labels

# make sure we are in same directory as the script itself
cd "$(dirname "[insert_php]include("webcam-project.inc");[/insert_php]")"

# waiting for incoming file
while [ ! -f inbox/webcam_*.jpg ]; do
  sleep 5
done

for filepath in inbox/webcam_*.jpg; do

  echo processing $filepath
  filename="${filepath##*/}"  
  ext="${filename##*.}"
  filename="${filename%.*}"
  filedate="${filename:7:4}-${filename:11:2}-${filename:13:2} ${filename:16:2}:${filename:18:2}"
  datestr="${filename:13:2}/${filename:11:2}/${filename:7:4} ${filename:16:2}:${filename:18:2}"
  DAYSTR="${filename:13:2}/${filename:11:2}/${filename:7:4}"
  HOURSTR="${filename:16:2}:${filename:18:2}" 

  # if you have a weather station, please add the temperature here:
  AIRTEMP="15°C"

  # write a copyright message into the image
  exiftool -overwrite_original -title='Webcam La Darsena, Lago di Como' \
    -copyright='La Darsena, Tremezzo' $filepath

  # create thumbnail without label
  convert $filepath -resize 192x108 "img/thb/$filename.jpg" \
    && touch "img/thb/$filename.jpg" --date="$filedate"

  # create label for 1920x1080 and hires
  convert \
    -size 322x162 xc:'#0000' \
    -fill "#000A" -draw "roundrectangle 0,0,322,162,15,15" \
    -fill "#949597" -gravity northwest -draw "line 20,125 300,125" \
    -font Courier-Bold -pointsize 19 \
    -fill black     -gravity northwest -annotate +21+138 "$datestr" \
    -fill "#949597" -gravity northwest -annotate +20+137 "$datestr" \
    -fill black     -gravity northeast -annotate +37+138 "$AIRTEMP" \
    -fill "#949597" -gravity northeast -annotate +38+137 "$AIRTEMP" \
    -font Courier-Bold -pointsize 13 \
    -fill black     -gravity northeast -annotate +19+138 "°C" \
    -fill "#949597" -gravity northeast -annotate +20+137 "°C" \
    logo/logo-ladarsena-webcam-280.png -gravity northwest -geometry +20+17 -composite \
    label-1920.png 

  # resize source image to 1920x1080 and put label on it
  convert $filepath -resize 1920x1080 label-1920.png -geometry +20+20 \
    -composite "img/hd/$filename.jpg" && touch "img/hd/$filename.jpg" \
    --date="$filedate"

  # put same label on hires image
  convert $filepath label-1920.png -geometry +20+20 -composite "img/hires/$filename.jpg" \
    && touch "img/hires/$filename.jpg" --date="$filedate"

  rm label-1920.png

  # the source file we just move to org
  touch $filepath --date="$filedate"
  mv $filepath img/org

  # get filename of latest file and soft link it
  LATEST=$(ls -t img/thb/webcam_*.jpg | head -1)
  CURRENT=$(basename $LATEST)
  ln -sf $CURRENT img/thb/webcam-ladarsena.jpg
  ln -sf $CURRENT img/hd/webcam-ladarsena.jpg
  ln -sf $CURRENT img/hires/webcam-ladarsena.jpg

done
/etc/systemd/system/image-processor.service
[Unit]
Description=Process incoming webcam images
After=network.target

[Service]
ExecStart=/var/www/darsenacam/webcam-processor.sh
User=root
Restart=always

[Install]
WantedBy=multi-user.target
maketimelapse.sh
#!/bin/bash
#
# maketimelapse.sh
# create a time lapse movie of all images from yesterday

# make sure we are in same directory as the script itself
cd "$(dirname "[insert_php]include("webcam-project.inc");[/insert_php]")"

# if script is calles without a date then use yesterdays date from 2 hours ago
 to make a clip of a certain date call "maketimelapse.sh 20151225"

if [ -z "" ]; then
 # yesterday
 CLIPDATE=`date --date='- 2 hours' +'%Y%m%d'`
 else
 CLIPDATE=
fi

# find jpg files and softlink them to tmp
find img/hd -type f  -name "webcam_$CLIPDATE*.jpg" -print | sort | \
  xargs -I {} sh -c 'ln -s "../img/hd/$(basename "")" \
  tmp/$(basename "");' - {}

# rename softlinks numeric ascending
x=1;
for i in tmp/*jpg; do 
  counter=$(printf %05d $x);
  mv $i tmp/img"$counter".jpg;
  x=$(($x+1));
done

# now create the video without audio
avconv -y -r 24 -f image2 -i tmp/img%05d.jpg -s hd720 -an input.mp4

rm -R tmp/*.jpg

filedate="${CLIPDATE:0:4}-${CLIPDATE:4:2}-${CLIPDATE:6:2} 23:59"
touch --date="${filedate}" webcam-ladarsena_$CLIPDATE.mp4
mv webcam-ladarsena_$CLIPDATE.mp4 img/movie/daily

(c) 2016 Peter Nägele, all code above is subject to GPL