Created
March 7, 2018 16:17
-
-
Save walker-tx/c475fd4064c0521058087a80c03bae10 to your computer and use it in GitHub Desktop.
Timelapse Controller from Raspberry Pi
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!~/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