This guide was originally written with instructions providing a ready made image, but became quite outdated. Rather than continually building new images from scratch, it's much easier to describe how you can put together all the software parts manually. 

The “Using It” page of this guide provides configuration and operation details…but if nothing else: it’s super especially important that you press and hold the halt button and then wait about 20 seconds before switching the camera off. Don’t just turn off the power when you’re done…otherwise you may lose images and/or corrupt the SD card and have to start over.

By default, the camera will capture a 1280x720 pixel JPEG image every 15 seconds, recording it to the SD card in the “timelapse” folder. You can change these options by inserting the card in your regular computer and editing a configuration file, explained on the “Using It” page.

Start with the lite version of the latest existing Raspberry Pi OS. It's easiest to use the Raspberry Pi Imager, which can configure Wi-Fi for you ahead of time.

Then install all the software and scripts needed for the camera project. The project has been updated to work on top of Blinka, so the easiest way to do this is to follow the installation page in the Blinka guide. This will get an virtual environment installed as well as Blinka.

This requires a Raspberry Pi with a network connection, which can be a nuisance if you’re working directly on the Pi Zero (rather than the Zero W). It’s usually easiest to set up the SD card on a more capable system (like a Raspberry Pi 3) and then move the finished card over to the Pi Zero; it’ll boot all the same.

The latest versions of the Raspberry Pi OS automatically expand the file system on the first boot. If you followed the Blinka guide and ran the install script, the camera should already be enabled. If not, you can enable it through the raspi-config utility.

Next download the timelapse script with the following commands:

sudo apt install -y wget
cd ~
wget https://github.com/adafruit/Adafruit_Learning_System_Guides/raw/main/Wearable_Time_Lapse_Camera/timelapse.py

Alternatively, if you’re logged in remotely via ssh, you can copy-and-paste the script below into that file. Since this will be located in the Pi’s /boot directory (which also shows up on regular Windows or Mac computers), you can save the script on your desktop computer and move it to the card later.

# SPDX-FileCopyrightText: 2024 Melissa leBlanc-Williams for Adafruit Industries
#
# SPDX-License-Identifier: MIT

#!/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.
# 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 = "/boot/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}" # pylint: disable=line-too-long
# COMMAND = "raspistill -n -w {width -h {height} -q {quality} -th none -t 250 -o {outfile}"

def main():
    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)
    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()

The file timelapse.py will contain our camera script. To run it, use the following command:

sudo -E env PATH=$PATH python3 ~/timelapse.py

To launch the script automatically on startup, edit the file /etc/rc.local and insert the following line near the end, just before the final exit 0. If you are using a different username than pi, you will want to change ~pi to ~yourusername.

sudo ~pi/env/bin/python3 ~pi/timelapse.py &

Finally, follow the Resizing the Raspberry Pi Boot Partition guide to expand the boot partition.

Alternatively, you can use your home folder and update the DEST path in the script variables. However, it may be slightly harder to access the photos on some systems.

Camera settings and such are explained on the “Using It” page.

This guide was first published on Jun 30, 2016. It was last updated on May 24, 2024.

This page (Software) was last updated on May 24, 2024.

Text editor powered by tinymce.