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
Table of contents
- Hardware
- Housing
- Software Camera Server
- Camera Settings
- Required packages
- Directory tree
- Scripts on Raspberry Pi
- systemd files on Raspberry Pi
- Web server side scripts
Hardware
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 with EF-S 18-55mm III kit | amazon.it | 330,00 EUR |
![]() |
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, 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 Space-saving cable, with 90° bent Micro-USB plug towards the back of the camera. |
partsdata.de | 6,00 EUR |
Raspberry Pi 2

![]() |
Raspberry Pi 2B | reichelt.de | 36,00 EUR |
![]() |
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 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 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 DN160 Ø160mm with end cover | local hardware store | 10,00 EUR |
![]() |
Mounting plate in stainless steel to carry all parts | local metalworker | 8,00 EUR |
![]() |
Gimbal mounting kit in stainless steel | local metalworker | 15,00 EUR |
![]() |
2 clamps Ø160mm stainless steel To attach the pipe to the gimbalk mounting kit. |
ebay.de | 22,00 EUR |
![]() |
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 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 used as a cooler fan |
reichelt.de | 2,00 EUR |
![]() |
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 Cut the cable in 2 pieces to connect both fans with USB power |
reichelt.de | 1,00 EUR |
![]() |
RPI mounting kit 20mm | reichelt.de | 4,00 EUR |
![]() |
Screw 1/4" to attach the camera | amazon.de | 2,00 EUR |
Software Camera Server

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
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
#!/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"
#!/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
#!/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
#!/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
[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
[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
[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
[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
#!/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