For my dad's birthday, I decided to make a system with a raspberry pi and camera that would take a time-lapse of the sun rising at our house in NH and send it in an email to my dad every day.
Once a year on his birthday it compiles a special email with a seasonal time-lapse. Read more below.
<aside> <img src="/icons/list_green.svg" alt="/icons/list_green.svg" width="40px" /> There are several steps that make this possible.
rapstill
time-lapse terminal command to take a photo every ten seconds for two hours.mp4
movieHere are some additional cool time-lapses that the Raspberry Pi captured
Look for the ducks!
Check out that mist!
2022: For my dad’s birthday this year, I added some new features to the program. Now, every year on his birthday it sends a special and completely automated email
<aside> ✉️ Happy Birthday Dad!
If my calculations are correct you are now 53 years old!
As an extra special birthday gift (which is completely automated) here is the seasonal time-lapse created from pictures taken from when I first gifted this to you until today
Check out the leaves the changing and falling!
Check out the leaves the changing and falling!
</aside>
2023: For my dad’s birthday this year, I added a feature that sends an automated email whenever a power outage is detected and the Raspberry Pi reboots. Not super important, but a fun little thing
<aside> ✉️ POWER ANOMALY DETECTED. Power recovered. Downtime 0:00:06.939611 (hh:mm:ss:...). All systems nominal.
</aside>
Over the past couple of years an additional 15 of my friends and family have requested and been added to the sunrise email sender. If you too would like a scenic 30 second NH sunrise time-lapse emailed to your inbox each morning feel free to reach out, and I’ll be happy to add you.
<aside> 👏 What people are saying
Good morning! I just want to thank you again for including me on the SH sunrise. It’s my daily meditation. I take deep breath and center while it’s downloading and playing. Namaste 🧘♂️- My AuntClick to see the code below
</aside>
import smtplib
import ssl
from email.mime.text import MIMEText
from email.utils import formataddr
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
import subprocess
import shutil
import os
import time
from astral import LocationInfo
from datetime import datetime, timedelta, date
from astral.sun import sun
import time
import sys
def uploadFile(upload_file):
gauth = GoogleAuth()
drive = GoogleDrive(gauth)
newFile = timelapseMode + "_timelapse_" + str(date.today()) + ".mp4"
print("uploading " + newFile + " ...", end="")
gfile = drive.CreateFile({'parents': [{'id': 'FOLDER_ID_GOES_HERE'}]}) # folder ID (from URL)
gfile.SetContentFile(upload_file)
gfile['title'] = newFile
gfile.Upload()
permission = gfile.InsertPermission({
'type': 'anyone',
'value': 'anyone',
'role': 'reader'})
link = gfile['alternateLink']
print("done")
return link
def remove(file):
try:
os.remove(file)
except:
pass
# User configuration
sender_email = "EMAIL_GOES_HERE"
sender_name = "NAME_GOES_HERE"
password = "PASSWORD_GOES_HERE"
receiver_emails = [] # list of emails
receiver_names = [] # list of reciever names
timelapseFilename = "timelapse.mp4"
timelapseFolder = "dailyTimelapse"
timelapseMode = sys.argv[1]
# actual lat and long go here (I have changed them)
latitude = 20
longitude = -60
# loc = LocationInfo(name='name', region='NH, USA', timezone="US/Eastern",
# latitude=latitude, longitude=longitude)
s = sun(loc.observer, date=datetime.today(), tzinfo=loc.timezone)
dawn = s["dawn"].replace(tzinfo=None)
dusk = s["dusk"].replace(tzinfo=None)
if dawn - datetime.now() < timedelta():
dawn += timedelta(days=1)
dusk += timedelta(days=1)
if timelapseMode == "sunrise":
targetTime = dawn
durationSeconds = round(timedelta(hours=2).total_seconds(), 2)
elif timelapseMode == "allday":
targetTime = dawn
durationSeconds = round((dusk-dawn).total_seconds(), 2)
else: # if timelapseMode == "now" # or anything else
targetTime = datetime(1990 , 2, 3, 2, 30, 0)
inputHours = float(sys.argv[2]) if len(sys.argv) == 3 else .5
durationSeconds = timedelta(hours=inputHours).total_seconds()
timelaspeMode = "now"
targetDiff = timedelta(seconds=1)
endVidLengthSeconds = 30
framerate = 24
secondsPerFrame = max(round(durationSeconds / framerate / endVidLengthSeconds, 2), 1.5)
totalPhotos = round(durationSeconds / secondsPerFrame)
print("================================================")
print("timelapse mode " + timelapseMode)
print("now " + str(datetime.now()))
print("target start time " + str(targetTime))
print("time duration (hours) " + str(durationSeconds / 3600))
print("seconds per frame " + str(secondsPerFrame))
print("total photos " + str(totalPhotos))
print("time till done (hours) " + str(round(durationSeconds / 3600 + totalPhotos/3600, 2)))
print("emailing to ", end="")
print(*receiver_names, sep=", ")
try:
shutil.rmtree(timelapseFolder)
except:
pass
remove(timelapseFilename)
if targetTime - datetime.now() > targetDiff:
print("waiting for %s" % str(targetTime - datetime.now()))
while targetTime - datetime.now() > targetDiff:
time.sleep(.5)
print("target time reached")
os.mkdir(timelapseFolder)
print("taking timelapse photos")
command = "raspistill -t {} -tl {} -awb auto -o {}/image%04d.jpg".format(durationSeconds*1000, secondsPerFrame*1000, timelapseFolder)
print(command)
subprocess.call(command, shell=True)
# from picamera import PiCamera
# camera = PiCamera()
# camera.start_preview()
# for i in range(totalPhotos):
# camera.capture(timelapseFolder + '/image{0:04d}.jpg'.format(i))
# time.sleep(secondsPerFrame)
print("stitching photos with ffmpeg")
command = "ffmpeg -r %i -f image2 -pattern_type glob -i '%s/image*.jpg'\\
-s 1280x720 -vcodec libx264 %s" % (framerate, timelapseFolder, timelapseFilename)
print(command)
subprocess.call(command, shell=True)
videoLink = uploadFile(timelapseFilename)
birthdate = date(1970 , 3, 10) # not my dad's real birthday
# if (date.today() - birthdate == timedelta(years=1)):
if date.today().strftime("%m%d") == birthdate.strftime("%m%d"):
email_body = '''
<h2 style="color: green">Happy Birthday Dad!</h2>
<p>%s timelapse on %s<p>
%s
''' % (loc.name, date.today(), videoLink)
else:
email_body = '''
<h2 style="color: green">%s timelapse %s </h2>
%s
''' % (loc.name, date.today(), videoLink)
# send emails(s)
for receiver_email, receiver_name in zip(receiver_emails, receiver_names):
print("Sending the email...")
# Configurating user's info
msg = MIMEMultipart()
msg['To'] = formataddr((receiver_name, receiver_email))
msg['From'] = formataddr((sender_name, sender_email))
msg['Subject'] = "%s timelapse %s"% (loc.name, date.today())
msg.attach(MIMEText(email_body, 'html'))
try:
# Creating a SMTP session | use 587 with TLS, 465 SSL and 25
server = smtplib.SMTP('smtp.gmail.com', 587)
# Encrypts the email
context = ssl.create_default_context()
server.starttls(context=context)
# We log in into our Google account
server.login(sender_email, password)
# Sending email from sender, to receiver with the email body
server.sendmail(sender_email, receiver_email, msg.as_string())
print('Email sent!')
except Exception as e:
print(f'Oh no! Something bad happened!n{e}')
break
finally:
print('Closing the server...')
server.quit()
<aside> <img src="/icons/home_blue.svg" alt="/icons/home_blue.svg" width="40px" /> Home
</aside>
<aside> <img src="/icons/document_green.svg" alt="/icons/document_green.svg" width="40px" /> Resume
</aside>
© Jesse Gilbert 2024