About

Raspberry Pi Remote Time Lapse System
Details about the project; including pictures, and code

Concept Development

This document lays out my goals for this project: Remote Camera for Camp

Coding

I originally had planned on using Bash to script the entire project, however I started running into problems with basic shell operations when it came to exectuing the first script I wrote. This script was to simply check if the pwd (present working directory) was ~/timelapse and if not, change to it.


#!/bin/bash
if [ "$PWD" = "$HOME/timelapse" ]
then
  echo "woot"
else
  cd $HOME/timelapse
fi

PiCamera Image Capture

After thinking some about how I know little about Bash compared to Python, I set out to disccover how to run the Raspberry Pi Camera Module with Python. Turns out there is a python module called PiCamera, and it is extremely versatile.

This is the code I am using to capture the image from the camera. Read the comments (lines denoted with "#") for information on what is going on in each block. You can also search google for any syntax unfamiliar to you, ex. "time.strftime python"
Contrary to popular belief: the "pound-sign" is actually called "crunch" or "hash" in computer terminology. Not "hashtag." To get the following code to work, I had to import the following modules: os, time, shutil, and picamera.

# Directory check
# First we want to check that the directory is correct, ftpupload relies on this
if os.getcwd() != "/home/pi/timelapse":
	os.chdir("/home/pi/timelapse")
	print ("Directory changed to %s \n " % os.getcwd())
else: print ("woot")

# SETUP
# Assign variables to make future changes easier
DAYS = 1
IMG_PER_HOUR = 4
IMGS = IMG_PER_HOUR * 24 * DAYS
timestr = time.strftime("%Y-%m-%d%I-%M-%S_%p_UTC")

# This function is where the actual image is captured, saved and renamed.
def capture_img(img) :
	with picamera.PiCamera() as camera:
		time.sleep(2)
		# Set image resolution, this resolution outputs an image around 600KB
		camera.resolution = (1280,960)
		# Add text annotation on black background, in this case we are inserting 
		# a formatted timestamp which displays the time in UTC 
		# (Universal Time Coordinated)
		camera.annotate_background = picamera.Color('black')
		camera.annotate_text = time.strftime("%Y-%m-%d %I:%M:%S %p UTC")
		camera.capture("/home/pi/timelapse/%s-%s.jpg" % (img, timestr))
		shutil.copyfile("/home/pi/timelapse/%s-%s.jpg" % (img, timestr),
				"/home/pi/timelapse/current.jpg")

# For loop that executes capture_img every 900s or 15 minutes
for img in range (IMGS) :
	# Note the time before the capture
	start = time.time()
	capture_img(img)
	print ("Image capture success: %s \n" % img)
	
	# Upload current image to FTP
	# Here we will upload the image just captured to an FTP server defined in 
	# ftpupload.py; ftpupload.py is executed by this line
	exec(open('/home/pi/ftpupload.py').read())
	print ("Image upload success: current.jpg \n")
	# Wait for the next capture. Note that we take into 
	# account the length of time it took to capture
	# the image when calculating the delay
	time.sleep(
		int(60 * 60 / IMG_PER_HOUR) - (time.time() - start)
	)

Uploading Images to Server

Next I needed a way of uploading the images to an FTP server, as the card in the Raspberry Pi, may not be large enough to hold a year's worth of images. This also allows easier access to the images, as well as the ability to upload them to a website. In order to do this I utilized the python module "ftplib." Ftplib provides a client side FTP protocol from which you can upload, download, and perform other basic file manipulations.
The code for the FTP script is below.

# Setup
# Define the upload function to execute when called
def upload(ftp, file):
    ftp.storbinary("STOR " + file, open(file, "rb"), 8192)

# Login to FTP server
ftp = FTP('ftp.example.com')

# We want to see the messages produced by ftplib
ftp.set_debuglevel(1)
ftp.getwelcome()
# Login credentials
ftp.login(user='username', passwd='password')

# Once connected to the server, cd (change directory) into FTP/timelapse
# the next script relies on an image called current.jpg being in this location
ftp.cwd('FTP/timelapse')

# Upload the image as binary
# EDIT - Need to inspect this code further, may not need to define
# function upload() 
file = open('current.jpg', 'rb')
ftp.storbinary('STOR current.jpg', file)
# Close server connection (disconnect)
file.close()

# Exit cleanly
ftp.quit()

Server-Side File Handling

Last but not least, we need a script running server-side to put the images where they need to go, in order to be useful. As this site hosts the Archive, we need to put them into an accessible folder for that, as well as putting the current image in a place where it can be inserted on the homepage. To do that I wrote this. I had planned to implement a watch system using os.stmtime() to check if the current.jpg file was modified, however I could not get it to work.
(Note: Indentation was modified to fit in allotted space.)

# SETUP
# Assign variables to make future changes easier, 
# as this script runs on the server, we can't
# set variables to automatically change
# when the capture script is changed
DAYS = 1
IMG_PER_HOUR = 4
IMGS = IMG_PER_HOUR * 24 * DAYS
timestr = time.strftime("%Y-%m-%d_%H-%M-%S_%p_UTC")

# Define function copy_img(), which will do the file handling
def copy_img(img) :
# Copy 'current.jpg' from /volume1/FTP/timelapse (where it was uploaded to)
# to /volume1/FTP/timelapse/Archive and rename to current time and date
   shutil.copyfile( shutil.copyfile('/volume1/FTP/timelapse/current.jpg',
				    '/volume1/FTP/timelapse/Archive/%s.jpg' % timestr)
# Copy 'current.jpg' again, but this time to /volume1/web/timelapse
# this is the copy that is displayed on the index/home page
        shutil.copyfile('/volume1/FTP/timelapse/current.jpg',
                        '/volume1/web/timelapse/current.jpg')

# For loop to run copy_img function every 15 minutes
for img in range (IMGS) :
    # Note the time before the op
    start = time.time()
    copy_img(img)
    print ("Image copy success \n")
    # Wait for the next capture. Note that we take into 
    # account the length of time it took to upload
    # the image when calculating the delay
    time.sleep(
        int(60 * 60 / IMG_PER_HOUR) - (time.time() - start + 2)
    )

Try Resizing your Browser

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Resources Used

The following resources were invaluable in enabling me to get the code working.