An open API service indexing awesome lists of open source software.

https://github.com/jwillikers/pi-camera

A DIY camera built using Raspberry Pi
https://github.com/jwillikers/pi-camera

camera diy exif gps photography photos pi pi-camera picamera2 python raspberry-pi rclone s3

Last synced: 12 months ago
JSON representation

A DIY camera built using Raspberry Pi

Awesome Lists containing this project

README

          

= Pi Camera
Jordan Williams
:experimental:
:icons: font
:keywords: camera gps photo pi picamera python raspberry
ifdef::env-github[]
:tip-caption: :bulb:
:note-caption: :information_source:
:important-caption: :heavy_exclamation_mark:
:caution-caption: :fire:
:warning-caption: :warning:
endif::[]
:AutoUpload: https://github.com/jwillikers/autoupload[AutoUpload]
:Getting-Started-with-HyperPixel-4-0: https://learn.pimoroni.com/article/getting-started-with-hyperpixel-4[Getting Started with HyperPixel 4.0]
:Exif: https://en.wikipedia.org/wiki/Exif[Exif]
:Immich: https://immich.app/[Immich]
:Immich-CLI: https://immich.app/docs/features/command-line-interface/[Immich CLI]
:just: https://github.com/casey/just[just]
:MinIO: https://min.io/[MinIO]
:picamera2: https://github.com/raspberrypi/picamera2[picamera2]
:pip-tools: https://github.com/jazzband/pip-tools[pip-tools]
:Raspberry-Pi-Camera: https://github.com/geerlingguy/pi-camera[Jeff Geerling's Raspberry Pi Camera]
:Rclone: https://rclone.org/[Rclone]
:systemd: https://systemd.io/[systemd]

image:https://github.com/jwillikers/pi-camera/actions/workflows/test.yaml/badge.svg[Tests, link=https://github.com/jwillikers/pi-camera/actions/workflows/test.yaml]
image:https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white[pre-commit, link=https://github.com/pre-commit/pre-commit]
image:https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json[Ruff, link=https://github.com/astral-sh/ruff]

A minimal Raspberry Pi camera that automatically syncs your photos.
It is based on {Raspberry-Pi-Camera} project.

ifdef::env-github[]
++++


Pi Camera Front Hand


++++
endif::[]

ifndef::env-github[]
image::pics/Pi Camera Front Hand.jpg[Pi Camera Front Hand, align=center]
endif::[]

== Overview

The Pi Camera is a minimal digital camera build which automatically uploads your photographs.
When a picture is taken and saved to the `~/Pictures` directory, its presence is automatically detected by {systemd}.
When an internet connection is next available, systemd uploads the photos to either S3-compatible object storage with {Rclone} or to {Immich} with the {Immich-CLI}.
The photos are then removed from local storage.
This is all accomplished with help of my {AutoUpload} project.
This repository documents how I've made the camera, the configuration files I've used, and the procedure to create the camera.

== Components

The Pi Camera is based off of the Raspberry Pi 4 and the Camera Module 3.
The camera uses Pimoroni's HyperPixel 4.0 screen which has good support in the Raspberry Pi kernel and full graphics acceleration.
The screen also works under Wayland.
A momentary push button is used to take pictures.
The HyperPixel 4.0 screen takes up all of the pins, only exposing an I2C bus.
The PCF8574 I2C GPIO Expander is used to connect the momentary push button and GPS to the Raspberry Pi.
An I2C GPS is used to incorporate {Exif} geolocation metadata in the pictures.

[NOTE]
====
Although the Raspberry Pi 5 is now out, it requires active cooling and a higher power input.
This makes it less suitable for a portable camera than the Raspberry Pi 4.
====

.Pi Camera Components
* https://www.raspberrypi.com/products/raspberry-pi-4-model-b/[Raspberry Pi 4 Model B] (2 GB RAM or better)
* https://www.raspberrypi.com/products/camera-module-3/[Raspberry Pi Camera Module 3]
* https://www.adafruit.com/product/1646[100mm Flex Cable for Raspberry Pi Camera]
* https://www.arducam.com/product/white-camera-enclosure-case-pi-cameras/[Camera Enclosure Case for Raspberry Pi Camera Module 3/V1/V2 and Arducam 16MP/64MP Camera]
* https://shop.pimoroni.com/products/hyperpixel-4?variant=12569485443155[Pimoroni HyperPixel 4.0 - Hi-Res Display for Raspberry Pi - Touch]
* https://www.adafruit.com/product/5545[Adafruit PCF8574 I2C GPIO Expander]
* https://www.adafruit.com/product/4209[STEMMA QT / Qwiic JST SH 4-pin to Premium Male Headers Cable - 150mm Long]
* https://www.adafruit.com/product/4399[STEMMA QT / Qwiic JST SH 4-Pin Cable - 50mm Long]
* https://www.adafruit.com/product/4415[Adafruit Mini GPS PA1010D - UART and I2C - STEMMA QT]
* https://amzn.to/3ijIj0C[Twidec 12mm momentary push button]
* A sufficiently large and performant microSD card.
The https://www.samsung.com/us/computing/memory-storage/memory-cards/pro-ultimate-adapter-microsdxc-128gb-mb-my128sa-am/[128GB Samsung Pro Ultimate] and https://www.samsung.com/us/computing/memory-storage/memory-cards/pro-endurance-adapter-microsdxc-128gb-mb-mj128ka-am/[128GB Samsung Pro Endurance] are two good options.
* A USB battery bank.
I'd recommend getting a battery with at least a 5000mAh capacity with the smallest form factor possible.
I use the https://www.adafruit.com/product/4288[USB Li-Ion Power Bank with 2 x 5V Outputs @ 2.1A - 5000mAh].
* A USB-C cable for powering the Pi.
* A case.
I found that LEGO Technics make a pretty sturdy case.
A minimal $13 LEGO Technics set was sufficient for making the enclosure for the camera.
I bought a second to make the case even better and add an enclosure for the battery.
I've been avoiding dealing with CAD files, but it should be possible to make some modifications to the CAD files from Jeff Geerling's https://github.com/geerlingguy/pi-camera[Raspberry Pi Camera] to account for the HyperPixel 4.0 screen.

== Build

The build is pretty straightforward.
It requires solder and a soldering iron to wire the PCF8574 to the momentary push button.

ifdef::env-github[]
++++


Pi Camera PCF8574


++++
endif::[]

ifndef::env-github[]
image::pics/Pi Camera PCF8574.jpg[Pi Camera PCF8574, align=center]
endif::[]

. Trim the length of the wires on the momentary push button.
They can be trimmed pretty short, but keep enough room to make up for any mistakes.
I only kept a couple of centimeters on each wire.
. Solder the leads of the momentary push button to the PCF8574 I2C GPIO Expander breakout.
Solder the black lead to ground and the red lead to `P0`.
. Attach the HyperPixel 4.0 to the Raspberry Pi.
Follow the instructions from {Getting-Started-with-HyperPixel-4-0}.
. Plug the male header pins on the STEMMA QT / Qwiic JST SH 4-pin to Premium Male Headers Cable to the HyperPixel 4.0.
With the screen face up, and the pins and micro HDMI ports facing towards you, the pins are ordered ground, clock, data, and power from left to right.
The associated cable colors are documented in the following table.

.Stemma Qt / Qwiic Cable Colors
[cols="1,1"]
|===
| Function | Color

| Ground | Black
| Clock | Yellow
| Data | Blue
| Power | Red
|===

. Attach the JST SH plug on STEMMA QT / Qwiic cable with male headers to the PCF8574 breakout.
It can be connected to either end of the board.
. Attach one of the JST SH plugs on the other STEMMA QT / Qwiic cable to the Adafruit Mini GPS PA1010D breakout.
It can be connected to either end of the board.
. Connect the flex cable to the 2-lane MIPI CSI camera port on the Raspberry Pi.
This port is next to the audio jack on the Raspberry Pi 4 Model B.
The side with the silver lines should face towards the micro HDMI ports.
The blue side should face towards the USB ports.
This process is documented by Raspberry Pi in the https://www.raspberrypi.com/documentation/accessories/camera.html#connecting-the-camera[Connecting the Camera] section of the Camera page.
+
[CAUTION]
====
Be gentle with the camera port, as they are fairly breakable.
====

. Connect the other end of the flex cable to the Raspberry Pi Camera Module 3.
The silver lines should be facing up, towards the camera's lens.
. Install the camera module in the camera enclosure case.
. Fit the case.
I'm not going to detail my ad-hoc case build, though hopefully the pictures provide some guidance.
However, be aware that the camera module should be positioned upright.
This is confusing because upright actually looks sideways with how the text is printed on the camera module.
This is important because the picamera2 library only allows flipping the image 180° at this time.
Other software techniques are necessary to flip the camera image 90° or 270°.
Issues https://github.com/raspberrypi/picamera2/issues/492[#492], https://github.com/raspberrypi/picamera2/issues/774[#774], and https://github.com/raspberrypi/picamera2/issues/792[#792] in the https://github.com/raspberrypi/picamera2[picamera2 Project] request this functionality.

== Install

. Install the 64-bit full version of https://www.raspberrypi.com/software/[Raspberry Pi OS] to a microSD card.
The configuration files assume the primary user is `pi-camera`, which can be configured when using Raspberry Pi Imager to write the image.
This project has been tested with Raspberry Pi OS 5 based on Debian Bookworm.
. Insert the microSD card into the Raspberry Pi.
. Boot the Raspberry Pi.
. Install {just} by following the instructions in the https://github.com/casey/just?tab=readme-ov-file#installation[installation section].
. Follow the instructions to configure the storage service and install the autoupload systemd units in the {AutoUpload} README to automatically upload photos in the `~/Pictures` directory.
The commands to enable the units should look similar to the following.
These use the _system_ units, though _user_ units work just as well.
+
Immich::
+
[,sh]
----
sudo systemctl enable --now autoupload-immich@$(systemd-escape --path ~/Pictures).path
----

Rclone::
+
[,sh]
----
sudo systemctl enable --now autoupload-rclone@$(systemd-escape --path ~/Pictures).path
----

. For security, be sure to disable password-based SSH authentication.
After your public key has been added to the `~/.ssh/authorized_keys` file on the Pi Camera, this can be configured in the `/etc/ssh/sshd_config` file.
You can follow the instructions in my https://github.com/jwillikers/openssh-config[OpenSSH Config] repository to accomplish this and a few other optimizations.

. Make the `~/Projects` directory.
+
[,sh]
----
mkdir --parents ~/Projects
----

. Clone this project's repository to the `~/Projects` directory.
+
[,sh]
----
git -C ~/Projects clone https://github.com/jwillikers/pi-camera.git
----

. Update the package lists.
+
[,sh]
----
sudo apt-get update
----

. Upgrade everything.
+
[,sh]
----
sudo apt-get --yes full-upgrade
----

. Change to the project's root directory.
+
[,sh]
----
cd ~/Projects/pi-camera
----

. Set up the environment with `just init`.
This will install dependencies and initialize the virtual environment.
+
[,sh]
----
just init
----

. Reboot for the updated `/boot/firmware/config.txt` file to take effect.
+
[,sh]
----
sudo systemctl reboot
----

. Use `just run` to run the `camera.py` Python script inside the virtual environment.
+
[,sh]
----
just run
----

. Install and activate the systemd service with `just install`.
+
[,sh]
----
just install
----

=== Configure Screen Orientation

One of the things that may need tweaked is the screen orientation.
This is technically configured in two places, the `/boot/firmware/config.txt` file, where it can be changed using the `rotate` `dtparam`, and additionally in Wayfire.
The configuration for Wayfire is documented in the https://www.raspberrypi.com/documentation/computers/configuration.html#setting-the-desktop-environment-resolution-and-rotation[Setting the desktop environment resolution and rotation section] of the Raspberry Pi Configuration documentation.
It is also described in the https://github.com/WayfireWM/wayfire-wiki/blob/master/Configuration.md[Configuration.md] file in the Wayfire repository.
The instructions here describe the basics necessary to rotate the screen.

. Determine the available display outputs with the `kmsprint` command.
Here, `DPI-1` corresponds to the HyperPixel 4.0.
+
[,sh]
----
kmsprint | grep Connector
Connector 0 (32) HDMI-A-1 (disconnected)
Connector 1 (42) HDMI-A-2 (disconnected)
Connector 2 (48) DPI-1 (connected)
----

. Use `wlr-randr` to rotate the display.
When running the command from an SSH connection, include the `WAYLAND_DISPLAY=wayland-1` variable as done here.
+
[,sh]
----
WAYLAND_DISPLAY=wayland-1 wlr-randr --output DPI-1 --transform 90
----

. To make the change permanent, configure the rotation in the Wayfire configuration file.
+
.~/.config/wayfire.ini
[,ini]
----
[output:DPI-1]
transform = 90
----

== HDR

The Raspberry Pi Camera Module 3 supports HDR, but only at a lower resolution.
HDR support has to toggled when `camera.py` isn't running.

. Show the available V4L subdevices.
+
[,sh]
----
ls /dev/v4l-subdev*
/dev/v4l-subdev0 /dev/v4l-subdev1 /dev/v4l-subdev2 /dev/v4l-subdev3
----

. To enable HDR support for the Raspberry Pi Camera Module 3, use the following command on one of the V4L subdevices.
In my case, this ended up being `/dev/v4l-subdev2`.
+
[,sh]
----
just hdr /dev/v4l-subdev2
----

. To disable HDR support for the Raspberry Pi Camera Module 3, use this command with the corresponding V4L subdevice.
+
[,sh]
----
just hdr /dev/v4l-subdev2 disable
----

== Development

. Run `just init-dev` to initialize the virtual environment for development.
This will install all of the necessary dependencies and the {pre-commit} hooks.
+
[,sh]
----
just init-dev
----

. Run the tests with https://docs.pytest.org/en/latest/[pytest] by running `just test`.
+
[,sh]
----
just test
----

. To update dependencies, run `just update`.
+
[,sh]
----
just update
----

. Use `just --list` to list other available tasks.
+
[,sh]
----
just --list
----

== todo

* mypy
* Make the camera application more robust.
It crashes really easily.
* Incorporate some sort of power button to safely shutdown.
* Add a NixOS configuration and build SD card images.

== See Also

* Jeff Geerling's https://github.com/geerlingguy/pi-camera[Raspberry Pi Camera]
* https://github.com/Gordon999/RPiCamGUI[RPiCamGUI]
* https://docs.circuitpython.org/projects/gps/en/latest/[Adafruit GPS Library Documentation]
* https://github.com/raspberrypi/picamera2/blob/main/apps/app_full.py[picamera2 Full App]

== Code of Conduct

The project's Code of Conduct is available in the link:CODE_OF_CONDUCT.adoc[Code of Conduct] file.

== License

This repository is licensed under the https://www.gnu.org/licenses/gpl-3.0.html[GPLv3], available in the link:LICENSE.adoc[license file].

© 2023-2024 Jordan Williams

== Authors

mailto:{email}[{author}]