Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Full Time-lapse Feature #27

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions behaviours/behaviour.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ def define_idle(self, method, interval, first=None):
'next': first
})

def check_idle(self, method):
for m in self.idle_methods:
if method == m['method']:
return True
return False

def remove_idle(self, method):
for m in self.idle_methods:
if method == m['method']:
Expand Down
110 changes: 58 additions & 52 deletions behaviours/picamera.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import atexit
from lib import pydrive
import datetime
from shutil import copyfile

try:
import RPi.GPIO as GPIO
Expand Down Expand Up @@ -38,10 +39,8 @@ class Picamera(Behaviour):
'^open camera$': 'open_camera',
'^close camera$': 'close_camera',
'^video$': 'open_and_take_video',
'^timelapse to drive': 'timelapse_to_drive',
'^timelapse$': 'timelapse',
'^stop timelapse$': 'stop_timelapse',
'pydrive': 'take_photo_pydrive'
'^(timelapse|time-lapse)$': 'timelapse',
'^stop (timelapse|time-lapse)$': 'stop_timelapse'
}

def __init__(self, **kwargs):
Expand Down Expand Up @@ -82,54 +81,6 @@ def close_camera(self):
return 'Could not close camera'
return None

def timelapse(self):
""" Take photo and send to admin every 5 minutes. """
self.define_idle(self.open_and_take_photo, 0) # take a photo every 5 minutes
return 'Timelapse started'

def timelapse_to_drive(self):
""" Take photo and send to google drive every 5 minutes. """
self.define_idle(self.take_photo_pydrive, 0) # take a photo every 5 minutes
return 'Timelapse to drive started'

def stop_timelapse(self):
if self.remove_idle(self.open_and_take_photo) or self.remove_idle(self.take_photo_pydrive):
return 'Timelapse stopped'
return 'No timelapse to stop'

def take_photo_pydrive(self):
self.open_camera(1920, 1080)
response = self.take_photo()
self.close_camera()

try:
drive = pydrive.authenticate()

pi_files_dir = pydrive.getFolderId(drive, 'root', 'Pi Files')
if pi_files_dir is None:
pi_files_dir = pydrive.createFolder(drive, 'root', 'Pi Files')

photos_dir = pydrive.getFolderId(drive, pi_files_dir, 'Photos')
if photos_dir is None:
photos_dir = pydrive.createFolder(drive, pi_files_dir, 'Photos')

today = datetime.datetime.now().strftime('%Y-%m-%d')
today_dir = pydrive.getFolderId(drive, photos_dir, today)
if today_dir is None:
today_dir = pydrive.createFolder(drive, photos_dir, today)

if today_dir:
file1 = drive.CreateFile(
{"parents": [{"kind": "drive#fileLink", "id": today_dir}],
'title': datetime.datetime.now().strftime('%Y-%m-%d %I:%M:%S %p')
})
file1.SetContentFile(self.jpg)
file1.Upload()
except Exception as e:
return e

return response

def open_and_take_photo(self):
""" Open camera if mounted to servo and take photo, then return to default position """
self.open_camera(1920, 1080)
Expand Down Expand Up @@ -228,3 +179,58 @@ def take_video(self):
os.remove(self.h264)
self.act.respond_video(self.mp4)
return None

def timelapse(self):
""" Take photo and send to google drive every 5 minutes.
This will work for a month before the local images have duplicate file names.
- I imagine the SD card will run out of space before that!
"""
if self.check_idle(self.take_timelapse_photo):
return 'A time-lapse is already running'
self.define_idle(self.take_timelapse_photo, 0) # take a photo every 5 minutes
return 'Time-lapse to drive started'

def stop_timelapse(self):
if self.remove_idle(self.take_timelapse_photo):
self.create_timelapse_video()
return 'Time-lapse stopped'
return 'No time-lapse to stop'

def take_timelapse_photo(self):
self.open_camera(1920, 1080)
response = self.take_photo()
self.close_camera()
self.upload_to_pydrive(
'Pi Files/Photos/' + datetime.datetime.now().strftime('%Y-%m-%d'),
datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
self.save_to_timelapse()
return response

def create_timelapse_video(self):
""" Create timelapse video from saved photos """
timelapse_dir = self.files + '/timelapse'
if os.path.exists(timelapse_dir):
os.system(
'avconv -framerate 20 -i ' + timelapse_dir + '/image%08d.jpg -vf format=yuv420p ' + self.files + '/timelapse.mp4')
self.act.respond_video(self.mp4)
os.remove(timelapse_dir)

def save_to_timelapse(self):
""" Save to local directory for duration of timelapse, will create video on stop """
timelapse_dir = self.files + '/timelapse'
try:
if not os.path.exists(timelapse_dir):
os.makedirs(timelapse_dir)
copyfile(self.jpg, timelapse_dir+'/image'+datetime.datetime.now().strftime('%d%H%M%S')+'.jpg')
except Exception as e:
return e

def upload_to_pydrive(self, location, name):
""" Upload image to google drive """
try:
drive = pydrive.authenticate()
today_dir = pydrive.get_or_create_folder(drive, location)
if today_dir:
pydrive.upload_jpg(drive, today_dir, name, self.jpg)
except Exception as e:
return e
28 changes: 24 additions & 4 deletions lib/pydrive.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,40 @@ def authenticate():
return GoogleDrive(gauth)


def getFolderId(drive, parent, folderName):
def get_folder_id(drive, parent, folder_name):
file_list = drive.ListFile({'q': "'%s' in parents and trashed=false" % parent}).GetList()
for f in file_list:
if f['mimeType'] == 'application/vnd.google-apps.folder' and f['title'] == folderName: # if folder
if f['mimeType'] == 'application/vnd.google-apps.folder' and f['title'] == folder_name: # if folder
return f['id']
return None


def createFolder(drive, parent, folderName):
folder_metadata = {"parents": [{"kind": "drive#fileLink", "id": parent}], 'title': folderName, 'mimeType': 'application/vnd.google-apps.folder'}
def create_folder(drive, parent, folder_name):
folder_metadata = {"parents": [{"kind": "drive#fileLink", "id": parent}], 'title': folder_name, 'mimeType': 'application/vnd.google-apps.folder'}
folder = drive.CreateFile(folder_metadata)
folder.Upload()
print('created folder ' + str(folder['id']))
return folder['id']


def get_or_create_folder(drive, folder_structure):
folders = folder_structure.split('/')
parent = 'root'
for folder in folders:
folder_id = get_folder_id(drive, parent, folder)
if folder_id is None:
folder_id = create_folder(drive, parent, folder)
parent = folder_id

return parent


def upload_jpg(drive, parent, title, file):
file1 = drive.CreateFile(
{"parents": [{"kind": "drive#fileLink", "id": parent}],
'title': title
})
file1.SetContentFile(file)
file1.Upload()