Skip to content

Commit

Permalink
Merge branch 'use-picamera2'
Browse files Browse the repository at this point in the history
  • Loading branch information
channingko-madden committed Dec 28, 2024
2 parents 9624a03 + 329650e commit ac7a108
Show file tree
Hide file tree
Showing 15 changed files with 748 additions and 240 deletions.
10 changes: 10 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.8.4
hooks:
# Run the linter.
- id: ruff
args: [ --fix ]
# Run the formatter.
- id: ruff-format
12 changes: 12 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.PHONY: format, pre_commit, test

SHELL=/bin/bash

format:
poetry run ruff format .

pre_commit:
poetry run pre-commit install

test:
poetry run pytest tests/
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
# rpi-camera-apps
Raspberry Pi apps that use the camera module
Raspberry Pi apps that use the camera module.

## Support
- Not compatible with Python2.
- Compatible with Raspbian Buster, and requires the Picamera module.
- Has not been tested on Raspbian Bullseye due to deprecation of Picamera. I hope to migrate to Bullseye once Picamera2 has a stable release.
## Dependencies

This project uses Picamera2, and therefore only supports Raspberry PI OS Bullseye or later.
See [here](https://github.com/raspberrypi/picamera2) for instructions for installing Picamera2.

I am using Poetry for dev dependencies only right now. I have not gotten
Poetry to work nicely and use the system installed Picamera2 package and
its dependencies. Trying to install Picamera2 and dependencies purely
through Poetry ends up freezing the Pi.
11 changes: 11 additions & 0 deletions apps/camera_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import time

from picamera2 import Picamera2

if __name__ == "__main__":
with Picamera2() as picam2:
camera_config = picam2.create_preview_configuration()
picam2.configure(camera_config)
picam2.start()
time.sleep(2)
picam2.capture_file("test.jpg")
87 changes: 45 additions & 42 deletions apps/email_time_lapse.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,24 @@
#!/usr/bin/python3

##
# file: email_time_lapse.py
# date: 2022-05-12
# author: Channing Ko-Madden
#
# description: This app takes pictures at a given time interval, and emails the pictures to you!

from datetime import datetime
import argparse
import smtplib
from rca.camera.time_lapse import TimeLapseCapture
from pathlib import Path

import rca.emails
from rca.camera.time_lapse import TimeLapseCapture
from rca.logger import create_rca_logger, get_logger

logger = get_logger(__name__)


def main(args):
def main(args: argparse.Namespace) -> int:
"""
Main function
Parameters:
-----------
args
Arguments returned by argparser.ArgumentParser.parse_args()
Returns 0 on successful execution, non-zero value indicates an error occured
Return:
-------
0 on successful execution, non-zero value indicates an error occured
Args:
args: CLI Arguments passed by the user
"""
if not args.gmail:
print("Missing -gmail argument")
Expand All @@ -39,50 +32,60 @@ def main(args):
print("Missing -to argument")
return 1

def send_callback(images):
create_rca_logger(log_file=args.logfile)

builder = rca.emails.HtmlImageBody(args.to, args.gmail, "Greetings!")

def send_callback(images: list[str]) -> None:
"""
Callback function for TimeLapseCapture that sends the images in an email
"""
builder = rca.emails.HtmlImageBody(args.to, args.gmail, "Greetings!")
msg = builder.build_msg(images)
try:
client = smtplib.SMTP('smtp.gmail.com', 587)
client = smtplib.SMTP("smtp.gmail.com", 587)
client.ehlo()
client.starttls()
client.ehlo()
client.login(user=args.gmail, password=args.password)
client.sendmail(args.gmail, args.to, msg.as_string())
print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + " : Email sent successfully")
except smtplib.SMTPException as error:
print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + " : SMTP Error occured" + str(error))
except OSError as error:
print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + " : OS Error occured" + str(error))
except BaseException as error:
print(datetime.now().strftime("%Y-%m-%d %H:%M:%S") + " : Unknown Error occured" + str(error))

picture_taker = TimeLapseCapture()
picture_taker.image_folder = args.folder
picture_taker.image_count = args.images
picture_taker.capture_delay = args.delay #seconds
logger.debug("Email sent successfully")
except smtplib.SMTPException:
logger.exception("SMTP Error occured")
except OSError:
logger.exception("OS Error occured")
except Exception:
logger.exception("Unknown Error occured")

picture_taker = TimeLapseCapture(image_folder=args.folder, image_count=args.images, capture_delay=args.delay)

while True:
print("Starting picture taking")
logger.debug("Starting picture taking")
picture_taker.sync_capture(send_callback)
print("Ending picture taking")

logger.debug("Ending picture taking")
return 0

if __name__ == '__main__':

if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-to", "-t", type=str, help="Provide email to send to", default="", required=True)
parser.add_argument("-gmail", "-g", type=str, help="Provide gmail to send from", default="", required=True)
parser.add_argument("-password", "-p", type=str, help="Provide Google App password", default="", required=True)
parser.add_argument("-delay", "-d", type=int, help="Provide delay between photos (sec)", default=10)
parser.add_argument("-images", "-i", type=int, help="Provide the number of images per email", default=6)
parser.add_argument("-folder",
"-f",
type=str,
help="Provide directory to temporarily store photos (ex. /home/pi/Pictures/)",
default="")
parser.add_argument(
"-folder",
"-f",
type=Path,
help="Provide directory to temporarily store photos (ex. /home/pi/Pictures/)",
default="./",
)
parser.add_argument(
"-logfile",
"-lf",
type=Path,
help="Provide path to file for writing logs (ex. /home/pi/log.txt)",
default=None,
required=False,
)

main(parser.parse_args())
Loading

0 comments on commit ac7a108

Please sign in to comment.