From 46550a403dde1bd2827bea7c2d847b28be6d1fb5 Mon Sep 17 00:00:00 2001 From: Melissa LeBlanc-Williams Date: Tue, 30 Apr 2024 11:51:05 -0700 Subject: [PATCH 1/3] Wrote Wearable Time Lapse Camera script in python --- Wearable_Time_Lapse_Camera/timelapse.py | 65 +++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Wearable_Time_Lapse_Camera/timelapse.py diff --git a/Wearable_Time_Lapse_Camera/timelapse.py b/Wearable_Time_Lapse_Camera/timelapse.py new file mode 100644 index 000000000..3ce2447ff --- /dev/null +++ b/Wearable_Time_Lapse_Camera/timelapse.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 + +import os +import re +import time +import board +import digitalio + +# Timelapse script, because timelapse options in raspistill don't power +# down the camera between captures. Script also provides a camera busy LED +# (v2 cameras don't include one) and a system halt button. +# 'gpio' command requires WiringPi: sudo apt-get install wiringpi +# Limitations: if DEST is FAT32 filesystem, max of 65535 files in directory; +# if DEST is ext4 filesystem, may have performance issues above 10K files. +# For intervals <2 sec, better just to use raspistill's timelapse feature. + +# Configurable stuff... +INTERVAL = 15 # Time between captures, in seconds +WIDTH = 1280 # Image width in pixels +HEIGHT = 720 # Image height in pixels +QUALITY = 51 # JPEG image quality (0-100) +DEST = "/home/pi/timelapse" # Destination directory (MUST NOT CONTAIN NUMBERS) +PREFIX = "img" # Image prefix (MUST NOT CONTAIN NUMBERS) +HALT_PIN = board.D21 # Halt button GPIO pin (other end to GND) +LED_PIN = board.D5 # Status LED pin (v2 Pi cam lacks built-in LED) +COMMAND = "libcamera-still -n --width {width} --height {height} -q {quality} --thumb none -t 250 -o {outfile}" +#COMMAND = "raspistill -n -w {width -h {height} -q {quality} -th none -t 250 -o {outfile}" +prevtime = 0 # Time of last capture (0 = do 1st image immediately) + +def main(): + global prevtime + halt = digitalio.DigitalInOut(HALT_PIN) + halt.switch_to_input(pull=digitalio.Pull.UP) + led = digitalio.DigitalInOut(LED_PIN) + led.switch_to_output() + + # Create destination directory (if not present) + os.makedirs(DEST, exist_ok=True) + + # Find index of last image (if any) in directory, start at this + 1 + files = os.listdir(DEST) + numbers = [int(re.search(r'\d+', f).group()) for f in files if f.startswith(PREFIX) and re.search(r'\d+', f)] + numbers.sort() + frame = numbers[-1] + 1 if numbers else 1 + currenttime = time.monotonic() + + while True: + while time.monotonic() < prevtime + INTERVAL: # Until next image capture time + currenttime = time.monotonic() + # Check for halt button -- hold >= 2 sec + while not halt.value: + if time.monotonic() >= currenttime + 2: + led.value = True + os.system('shutdown -h now') + outfile = f"{DEST}/{PREFIX}{frame:05}.jpg" + # echo $OUTFILE + led.value = True + os.system(COMMAND.format(width=WIDTH, height=HEIGHT, quality=QUALITY, outfile=outfile)) + led.value = False + frame += 1 # Increment image counter + prevtime = currenttime # Save image cap time + + +if __name__ == "__main__": + main() \ No newline at end of file From 584cc5b123b28930689eacdf802433360ec71fc8 Mon Sep 17 00:00:00 2001 From: Melissa LeBlanc-Williams Date: Tue, 30 Apr 2024 12:10:31 -0700 Subject: [PATCH 2/3] Add spdx and lint --- Wearable_Time_Lapse_Camera/timelapse.py | 47 +++++++++++++++---------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/Wearable_Time_Lapse_Camera/timelapse.py b/Wearable_Time_Lapse_Camera/timelapse.py index 3ce2447ff..901057bc5 100644 --- a/Wearable_Time_Lapse_Camera/timelapse.py +++ b/Wearable_Time_Lapse_Camera/timelapse.py @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2024 Melissa leBlanc-Williams for Adafruit Industries +# +# SPDX-License-Identifier: MIT + #!/usr/bin/env python3 import os @@ -15,51 +19,56 @@ # For intervals <2 sec, better just to use raspistill's timelapse feature. # Configurable stuff... -INTERVAL = 15 # Time between captures, in seconds -WIDTH = 1280 # Image width in pixels -HEIGHT = 720 # Image height in pixels -QUALITY = 51 # JPEG image quality (0-100) -DEST = "/home/pi/timelapse" # Destination directory (MUST NOT CONTAIN NUMBERS) -PREFIX = "img" # Image prefix (MUST NOT CONTAIN NUMBERS) -HALT_PIN = board.D21 # Halt button GPIO pin (other end to GND) -LED_PIN = board.D5 # Status LED pin (v2 Pi cam lacks built-in LED) +INTERVAL = 15 # Time between captures, in seconds +WIDTH = 1280 # Image width in pixels +HEIGHT = 720 # Image height in pixels +QUALITY = 51 # JPEG image quality (0-100) +DEST = "/home/pi/timelapse" # Destination directory (MUST NOT CONTAIN NUMBERS) +PREFIX = "img" # Image prefix (MUST NOT CONTAIN NUMBERS) +HALT_PIN = board.D21 # Halt button GPIO pin (other end to GND) +LED_PIN = board.D5 # Status LED pin (v2 Pi cam lacks built-in LED) COMMAND = "libcamera-still -n --width {width} --height {height} -q {quality} --thumb none -t 250 -o {outfile}" -#COMMAND = "raspistill -n -w {width -h {height} -q {quality} -th none -t 250 -o {outfile}" -prevtime = 0 # Time of last capture (0 = do 1st image immediately) +# COMMAND = "raspistill -n -w {width -h {height} -q {quality} -th none -t 250 -o {outfile}" def main(): - global prevtime + prevtime = 0 # Time of last capture (0 = do 1st image immediately) halt = digitalio.DigitalInOut(HALT_PIN) halt.switch_to_input(pull=digitalio.Pull.UP) led = digitalio.DigitalInOut(LED_PIN) led.switch_to_output() - # Create destination directory (if not present) + # Create destination directory (if not present) os.makedirs(DEST, exist_ok=True) # Find index of last image (if any) in directory, start at this + 1 files = os.listdir(DEST) - numbers = [int(re.search(r'\d+', f).group()) for f in files if f.startswith(PREFIX) and re.search(r'\d+', f)] + numbers = [ + int(re.search(r"\d+", f).group()) + for f in files + if f.startswith(PREFIX) and re.search(r"\d+", f) + ] numbers.sort() frame = numbers[-1] + 1 if numbers else 1 currenttime = time.monotonic() while True: - while time.monotonic() < prevtime + INTERVAL: # Until next image capture time + while time.monotonic() < prevtime + INTERVAL: # Until next image capture time currenttime = time.monotonic() # Check for halt button -- hold >= 2 sec while not halt.value: if time.monotonic() >= currenttime + 2: led.value = True - os.system('shutdown -h now') + os.system("shutdown -h now") outfile = f"{DEST}/{PREFIX}{frame:05}.jpg" # echo $OUTFILE led.value = True - os.system(COMMAND.format(width=WIDTH, height=HEIGHT, quality=QUALITY, outfile=outfile)) + os.system( + COMMAND.format(width=WIDTH, height=HEIGHT, quality=QUALITY, outfile=outfile) + ) led.value = False - frame += 1 # Increment image counter - prevtime = currenttime # Save image cap time + frame += 1 # Increment image counter + prevtime = currenttime # Save image cap time if __name__ == "__main__": - main() \ No newline at end of file + main() From d09369e1bf7df636dd84408910230cd2566eb949 Mon Sep 17 00:00:00 2001 From: Melissa LeBlanc-Williams Date: Tue, 30 Apr 2024 12:14:49 -0700 Subject: [PATCH 3/3] disable line too long error --- Wearable_Time_Lapse_Camera/timelapse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Wearable_Time_Lapse_Camera/timelapse.py b/Wearable_Time_Lapse_Camera/timelapse.py index 901057bc5..6911dd6cb 100644 --- a/Wearable_Time_Lapse_Camera/timelapse.py +++ b/Wearable_Time_Lapse_Camera/timelapse.py @@ -27,7 +27,7 @@ PREFIX = "img" # Image prefix (MUST NOT CONTAIN NUMBERS) HALT_PIN = board.D21 # Halt button GPIO pin (other end to GND) LED_PIN = board.D5 # Status LED pin (v2 Pi cam lacks built-in LED) -COMMAND = "libcamera-still -n --width {width} --height {height} -q {quality} --thumb none -t 250 -o {outfile}" +COMMAND = "libcamera-still -n --width {width} --height {height} -q {quality} --thumb none -t 250 -o {outfile}" # pylint: disable=line-too-long # COMMAND = "raspistill -n -w {width -h {height} -q {quality} -th none -t 250 -o {outfile}" def main():