2017-07-26

Take periodic photos using Pi camera and upload to Google Drive


Taking photos using the Pi camera is easy.  But how to allow remote access of the photo is a headache.  I do not want to Port Forwarding in my router (especially on SSH ports) because I think my Pi is not yet appropriately hardened.  I decide to upload the photos to the cloud.

Google has well-documented API for the Google Drive access.  In particular, I love Petter Rasmussen's gdrive, which is a CLI (command-line-interface) client for many Operating Systems because it is a static binary which does not need external libraries.

I have tried the Windows 64 bit build and the Raspberry Pi build and it works.  For the Windows build, I even try it behind the proxy server of my company and it works after I set up the http_proxy environment variable.

The github page of the gdrive already provides extensive documentation (with examples) and it is easy to adopt.  The following are my major usage:

(1) Initial setup

gdrive about

gdrive will print out a URL.  Using browser to launch the URL and enter the account password, Google will print out a verification code.  I will enter the verification code to the CLI.

There is documentation on Service Account, which is said to make server-to-Google access with password-less access.  But I find that even using the verification code approach, I find gdrive can refresh the token file automatically.  In other words, I only need to input the verification code once.  Therefore I finally do not bother to set up a Service Account.

(2) List File details

gdrive list --query "name = 'file_name_or_folder_name' "

C:\PortableApps\gdrive>gdrive-windows-x64.exe list --query "name = 'PI_PHOTO_00.jpg' "
Id                             Name              Type   Size     Created
xxxxxxxxxxxxxxxxxxxxxxxxxxxx   PI_PHOTO_00.jpg   bin    4.8 MB   2017-07-26 10:00:16

C:\PortableApps\gdrive>gdrive-windows-x64.exe list --query "name = 'pi-photos' "
Id                             Name        Type   Size   Created
xxxxxxxxxxxxxxxxxxxxxxxxxxxx   pi-photos   dir           2017-07-21 19:50:23

(3) List Files inside a folder

gdrive list --query " 'Parent_Folder_Id' in parents"

C:\PortableApps\gdrive>gdrive-windows-x64.exe list --query " '0Bzo1pJKfp9QEdVZFdVV2RTV2RVE' in parents "
Id                             Name              Type   Size     Created
xxxxxxxxxxxxxxxxxxxxxxxxxxxx   PI_PHOTO_35.jpg   bin    4.8 MB   2017-07-26 10:35:12
xxxxxxxxxxxxxxxxxxxxxxxxxxxx   PI_PHOTO_30.jpg   bin    4.7 MB   2017-07-26 10:30:12

(4) Upload File to specified folder

gdrive --parent Parent_Folder_Id Upload_Filename

(5) Delete File

gdrive delete  File_Id

I then start to code my bash script (which will be run by cron periodically) to take photo and then upload the photo.  I use the minute digits to name my photo filename and originally thought that this nomenclature can automatically recycle my photo copies without an explicit housekeeping job.  But I am wrong.  I find Google Drive allow multiple copies of the same filename (even not using the versioning feature) and these multiple copies will be assigned with different File-Id.

Worst still I find gdrive has no direct command to delete a file (or files) by filename.  I need to first list the File_id by the inputted filename and then delete them (if more than one) one-by-one.  The logic is:

gdrive list --no-header --query "name = 'Filename' " | awk '{print $1}' | xargs -n 1 gdrive delete

The xargs command is to ensure the gdrive is executed one-by-one

The following is my script:

#!/bin/bash
# use 00-59 minutes for filename recycling
DATE_MM=$(date +"%M")
cd  /home/pi/photos
raspistill -n -o PI_PHOTO_${DATE_MM}.jpg
# delete duplicated copies at Google drive
/home/pi/gdrive-linux-rpi list --no-header --query "name = 'PI_PHOTO_${DATE_MM}.jpg'" | awk '{print $1}' | xargs -n 1 /home/pi/gdrive-linux-rpi delete
# upload to pi_photos folder at Google Drive
/home/pi/gdrive-linux-rpi upload --parent xxxxxxxxxxxxxxxxxxxxxxxxxxxx --delete PI_PHOTO_${DATE_MM}.jpg