Skip to content

Instantly share code, notes, and snippets.

@walker-tx
Created March 7, 2018 16:17
Show Gist options
  • Save walker-tx/c475fd4064c0521058087a80c03bae10 to your computer and use it in GitHub Desktop.
Save walker-tx/c475fd4064c0521058087a80c03bae10 to your computer and use it in GitHub Desktop.
Timelapse Controller from Raspberry Pi
#!~/VEnvironments/PiLapseCam/
# TODO
# 1.) TRIGGER CAMERA.............................DONE
# 2.) MOVE IMAGES FROM SD CARD TO SPEC. FOLDER...DONE
# 2.) RENAME FILE TO DATE/TIME USING EXIF........DONE
# 3.) INTERVELOMETER ACCOUNTING FOR DAYS, HOURS..DONE
# 4.) GRAPHICAL USER INTERFACE
# 5.) EMAIL ERROR REPORTING
# 7.) GUIDE CAMERA CONTROLS
# 6.) UPLOAD TO CLOUD STORAGE
# Imports from Python 3.4 Native Library
from __future__ import print_function
import datetime as dt
import time
import logging
import os
import subprocess
import sys
import subprocess, signal
import shutil
# Imports from PyPi Libraries
import gphoto2 as gp
import exifread
from apscheduler.schedulers.background import BlockingScheduler
# Class Variables
##Photo save root folder on local device
photo_local_root = '/home/pi/Desktop/images'
##Daily start, finish and interval times for timelapse
START_HOUR = '7'
FINISH_HOUR = '16'
INTERVAL = 15 #Seconds
##Calculated. Don't touch these!
SCHEDULER = BlockingScheduler(timezone='US/Central')
HOUR_BOUNDS = START_HOUR + '-' + FINISH_HOUR
logging.basicConfig(filename='test.log', level=logging.INFO, \
format='%(asctime)s:%(levelname)s:%(name)s:%(message)s')
#
# Kill the 'gvfsd-gphoto2' process
#
def killGphoto():
print("***")
print("Killing Gphoto2...")
p = subprocess.Popen(['killall', 'gvfsd-gphoto2'])
out, err = p.communicate()
print("Killall Command Delivered...")
print("***")
#
# Convert the exifread object to a readable date and time
#
def EXIF_DateTimetoStr(exifread):
#Convert the IfDTag to string then
#chop off text before '=' and after '@'
result = repr(exifread).split('=', 1)[-1].split('@',)[0]
#Strip of leading and tailing spaces then
#replace spaces with underscores and colons with dashes
#within the date portion
result = result.strip().replace(' ', '_').replace(':', '-', 2)
return result
#
# Convert the exifread object to a readable date
#
def EXIF_DatetoStr(exifread):
#Convert the IfDTag to string then
#chop off text '=' and before, '@' and after
result = repr(exifread).split('=', 1)[-1].split('@',)[0]
#Strip of leading and tailing spaces then
#chop off last space and after
result = result.strip().split(' ',)[0]
#Strip spaces one final time
#Replace colons with dashes
result = result.strip().replace(':', '-')
return result
#
# Capture Sequence
#
def captureSave(camera, context):
#Capture Action
file_path = gp.check_result(gp.gp_camera_capture(
camera, gp.GP_CAPTURE_IMAGE, context))
#Making Target Save photo_local_root Dir
target = os.path.join(photo_local_root, file_path.name)
#GP_FILE_TYPE_NORMAL for JPEG; GP_FILE_TYPE_RAW for RAW
camera_file = gp.check_result(gp.gp_camera_file_get(
camera, file_path.folder, file_path.name,
gp.GP_FILE_TYPE_RAW, context))
gp.check_result(gp.gp_file_save(camera_file, target))
gp.check_result(gp.gp_camera_file_delete(camera, file_path.folder,
file_path.name, context))
#Rename Based on EXIF Data
target_open = open(target, 'rb')
tags = exifread.process_file(target_open, \
stop_tag='EXIF DateTimeOriginal')
for tag in tags.keys():
#Only Perform Following if is Date/Time
#Change file extension here for RAW/JPEG
if tag in ('EXIF DateTimeOriginal'):
file_name = EXIF_DateTimetoStr(tags[tag]) + '.NEF'
file_dir = os.path.join(photo_local_root,
EXIF_DatetoStr(tags[tag]))
#Check existence of file_dir, the create it if false
if not os.path.exists(file_dir):
os.makedirs(file_dir)
#Rename and move the captured image then sleep
shutil.move(target, os.path.join(file_dir, file_name))
time.sleep(3)
#
# Main Function
#
def main():
#Kill gphoto2
killGphoto()
#GP2 Log and Camera Setup
gp.check_result(gp.use_python_logging())
context = gp.gp_context_new()
camera = gp.check_result(gp.gp_camera_new())
gp.check_result(gp.gp_camera_init(camera, context))
#Declaration of Interval Schedulers
SCHEDULER.add_job(captureSave, 'cron', args=[camera,context], \
day_of_week='mon-fri', second='*/'+str(INTERVAL), \
hour=HOUR_BOUNDS)
print('Press Ctrl+{0} to exit'.format( \
'Break' if os.name == 'nt' else 'C'))
try:
SCHEDULER.start()
except (KeyboardInterrupt, SystemExit):
SCHEDULER.remove_job('intervelo')
pass
#Close Camera
gp.check_result(gp.gp_camera_exit(camera, context))
return 0
if __name__ == "__main__":
print("***PROCESS CLOSING***")
sys.exit(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment