{"id":18929137,"url":"https://github.com/jwillikers/pi-camera","last_synced_at":"2026-03-16T12:30:16.731Z","repository":{"id":219612530,"uuid":"710786121","full_name":"jwillikers/pi-camera","owner":"jwillikers","description":"A DIY camera built using Raspberry Pi","archived":false,"fork":false,"pushed_at":"2024-12-02T16:56:55.000Z","size":16212,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-14T21:38:56.658Z","etag":null,"topics":["camera","diy","exif","gps","photography","photos","pi","pi-camera","picamera2","python","raspberry-pi","rclone","s3"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jwillikers.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.adoc","code_of_conduct":"CODE_OF_CONDUCT.adoc","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-10-27T12:42:54.000Z","updated_at":"2024-12-02T16:56:58.000Z","dependencies_parsed_at":"2024-11-08T11:43:24.304Z","dependency_job_id":null,"html_url":"https://github.com/jwillikers/pi-camera","commit_stats":null,"previous_names":["jwillikers/pi-camera"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwillikers%2Fpi-camera","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwillikers%2Fpi-camera/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwillikers%2Fpi-camera/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwillikers%2Fpi-camera/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jwillikers","download_url":"https://codeload.github.com/jwillikers/pi-camera/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239927824,"owners_count":19719835,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["camera","diy","exif","gps","photography","photos","pi","pi-camera","picamera2","python","raspberry-pi","rclone","s3"],"created_at":"2024-11-08T11:30:20.399Z","updated_at":"2026-03-16T12:30:16.688Z","avatar_url":"https://github.com/jwillikers.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"= Pi Camera\nJordan Williams \u003cjordan@jwillikers.com\u003e\n:experimental:\n:icons: font\n:keywords: camera gps photo pi picamera python raspberry\nifdef::env-github[]\n:tip-caption: :bulb:\n:note-caption: :information_source:\n:important-caption: :heavy_exclamation_mark:\n:caution-caption: :fire:\n:warning-caption: :warning:\nendif::[]\n:AutoUpload: https://github.com/jwillikers/autoupload[AutoUpload]\n:Getting-Started-with-HyperPixel-4-0: https://learn.pimoroni.com/article/getting-started-with-hyperpixel-4[Getting Started with HyperPixel 4.0]\n:Exif: https://en.wikipedia.org/wiki/Exif[Exif]\n:Immich: https://immich.app/[Immich]\n:Immich-CLI: https://immich.app/docs/features/command-line-interface/[Immich CLI]\n:just: https://github.com/casey/just[just]\n:MinIO: https://min.io/[MinIO]\n:picamera2: https://github.com/raspberrypi/picamera2[picamera2]\n:pip-tools: https://github.com/jazzband/pip-tools[pip-tools]\n:Raspberry-Pi-Camera: https://github.com/geerlingguy/pi-camera[Jeff Geerling's Raspberry Pi Camera]\n:Rclone: https://rclone.org/[Rclone]\n:systemd: https://systemd.io/[systemd]\n\nimage:https://github.com/jwillikers/pi-camera/actions/workflows/test.yaml/badge.svg[Tests, link=https://github.com/jwillikers/pi-camera/actions/workflows/test.yaml]\nimage:https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit\u0026logoColor=white[pre-commit, link=https://github.com/pre-commit/pre-commit]\nimage: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]\n\nA minimal Raspberry Pi camera that automatically syncs your photos.\nIt is based on {Raspberry-Pi-Camera} project.\n\nifdef::env-github[]\n++++\n\u003cp align=\"center\"\u003e\n  \u003cimg  alt=\"Pi Camera Front Hand\" src=\"pics/Pi Camera Front Hand.jpg?raw=true\"/\u003e\n\u003c/p\u003e\n++++\nendif::[]\n\nifndef::env-github[]\nimage::pics/Pi Camera Front Hand.jpg[Pi Camera Front Hand, align=center]\nendif::[]\n\n== Overview\n\nThe Pi Camera is a minimal digital camera build which automatically uploads your photographs.\nWhen a picture is taken and saved to the `~/Pictures` directory, its presence is automatically detected by {systemd}.\nWhen 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}.\nThe photos are then removed from local storage.\nThis is all accomplished with help of my {AutoUpload} project.\nThis repository documents how I've made the camera, the configuration files I've used, and the procedure to create the camera.\n\n== Components\n\nThe Pi Camera is based off of the Raspberry Pi 4 and the Camera Module 3.\nThe camera uses Pimoroni's HyperPixel 4.0 screen which has good support in the Raspberry Pi kernel and full graphics acceleration.\nThe screen also works under Wayland.\nA momentary push button is used to take pictures.\nThe HyperPixel 4.0 screen takes up all of the pins, only exposing an I2C bus.\nThe PCF8574 I2C GPIO Expander is used to connect the momentary push button and GPS to the Raspberry Pi.\nAn I2C GPS is used to incorporate {Exif} geolocation metadata in the pictures.\n\n[NOTE]\n====\nAlthough the Raspberry Pi 5 is now out, it requires active cooling and a higher power input.\nThis makes it less suitable for a portable camera than the Raspberry Pi 4.\n====\n\n.Pi Camera Components\n* https://www.raspberrypi.com/products/raspberry-pi-4-model-b/[Raspberry Pi 4 Model B] (2 GB RAM or better)\n* https://www.raspberrypi.com/products/camera-module-3/[Raspberry Pi Camera Module 3]\n* https://www.adafruit.com/product/1646[100mm Flex Cable for Raspberry Pi Camera]\n* 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]\n* https://shop.pimoroni.com/products/hyperpixel-4?variant=12569485443155[Pimoroni HyperPixel 4.0 - Hi-Res Display for Raspberry Pi - Touch]\n* https://www.adafruit.com/product/5545[Adafruit PCF8574 I2C GPIO Expander]\n* https://www.adafruit.com/product/4209[STEMMA QT / Qwiic JST SH 4-pin to Premium Male Headers Cable - 150mm Long]\n* https://www.adafruit.com/product/4399[STEMMA QT / Qwiic JST SH 4-Pin Cable - 50mm Long]\n* https://www.adafruit.com/product/4415[Adafruit Mini GPS PA1010D - UART and I2C - STEMMA QT]\n* https://amzn.to/3ijIj0C[Twidec 12mm momentary push button]\n* A sufficiently large and performant microSD card.\nThe 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.\n* A USB battery bank.\nI'd recommend getting a battery with at least a 5000mAh capacity with the smallest form factor possible.\nI use the https://www.adafruit.com/product/4288[USB Li-Ion Power Bank with 2 x 5V Outputs @ 2.1A - 5000mAh].\n* A USB-C cable for powering the Pi.\n* A case.\nI found that LEGO Technics make a pretty sturdy case.\nA minimal $13 LEGO Technics set was sufficient for making the enclosure for the camera.\nI bought a second to make the case even better and add an enclosure for the battery.\nI'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.\n\n== Build\n\nThe build is pretty straightforward.\nIt requires solder and a soldering iron to wire the PCF8574 to the momentary push button.\n\nifdef::env-github[]\n++++\n\u003cp align=\"center\"\u003e\n  \u003cimg  alt=\"Pi Camera PCF8574\" src=\"pics/Pi Camera PCF8574.jpg?raw=true\"/\u003e\n\u003c/p\u003e\n++++\nendif::[]\n\nifndef::env-github[]\nimage::pics/Pi Camera PCF8574.jpg[Pi Camera PCF8574, align=center]\nendif::[]\n\n. Trim the length of the wires on the momentary push button.\nThey can be trimmed pretty short, but keep enough room to make up for any mistakes.\nI only kept a couple of centimeters on each wire.\n. Solder the leads of the momentary push button to the PCF8574 I2C GPIO Expander breakout.\nSolder the black lead to ground and the red lead to `P0`.\n. Attach the HyperPixel 4.0 to the Raspberry Pi.\nFollow the instructions from {Getting-Started-with-HyperPixel-4-0}.\n. Plug the male header pins on the STEMMA QT / Qwiic JST SH 4-pin to Premium Male Headers Cable to the HyperPixel 4.0.\nWith 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.\nThe associated cable colors are documented in the following table.\n\n.Stemma Qt / Qwiic Cable Colors\n[cols=\"1,1\"]\n|===\n| Function | Color\n\n| Ground | Black\n| Clock | Yellow\n| Data | Blue\n| Power | Red\n|===\n\n. Attach the JST SH plug on STEMMA QT / Qwiic cable with male headers to the PCF8574 breakout.\nIt can be connected to either end of the board.\n. Attach one of the JST SH plugs on the other STEMMA QT / Qwiic cable to the Adafruit Mini GPS PA1010D breakout.\nIt can be connected to either end of the board.\n. Connect the flex cable to the 2-lane MIPI CSI camera port on the Raspberry Pi.\nThis port is next to the audio jack on the Raspberry Pi 4 Model B.\nThe side with the silver lines should face towards the micro HDMI ports.\nThe blue side should face towards the USB ports.\nThis 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.\n+\n[CAUTION]\n====\nBe gentle with the camera port, as they are fairly breakable.\n====\n\n. Connect the other end of the flex cable to the Raspberry Pi Camera Module 3.\nThe silver lines should be facing up, towards the camera's lens.\n. Install the camera module in the camera enclosure case.\n. Fit the case.\nI'm not going to detail my ad-hoc case build, though hopefully the pictures provide some guidance.\nHowever, be aware that the camera module should be positioned upright.\nThis is confusing because upright actually looks sideways with how the text is printed on the camera module.\nThis is important because the picamera2 library only allows flipping the image 180° at this time.\nOther software techniques are necessary to flip the camera image 90° or 270°.\nIssues 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.\n\n== Install\n\n. Install the 64-bit full version of https://www.raspberrypi.com/software/[Raspberry Pi OS] to a microSD card.\nThe configuration files assume the primary user is `pi-camera`, which can be configured when using Raspberry Pi Imager to write the image.\nThis project has been tested with Raspberry Pi OS 5 based on Debian Bookworm.\n. Insert the microSD card into the Raspberry Pi.\n. Boot the Raspberry Pi.\n. Install {just} by following the instructions in the https://github.com/casey/just?tab=readme-ov-file#installation[installation section].\n. 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.\nThe commands to enable the units should look similar to the following.\nThese use the _system_ units, though _user_ units work just as well.\n+\nImmich::\n+\n[,sh]\n----\nsudo systemctl enable --now autoupload-immich@$(systemd-escape --path ~/Pictures).path\n----\n\nRclone::\n+\n[,sh]\n----\nsudo systemctl enable --now autoupload-rclone@$(systemd-escape --path ~/Pictures).path\n----\n\n. For security, be sure to disable password-based SSH authentication.\nAfter 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.\nYou can follow the instructions in my https://github.com/jwillikers/openssh-config[OpenSSH Config] repository to accomplish this and a few other optimizations.\n\n. Make the `~/Projects` directory.\n+\n[,sh]\n----\nmkdir --parents ~/Projects\n----\n\n. Clone this project's repository to the `~/Projects` directory.\n+\n[,sh]\n----\ngit -C ~/Projects clone https://github.com/jwillikers/pi-camera.git\n----\n\n. Update the package lists.\n+\n[,sh]\n----\nsudo apt-get update\n----\n\n. Upgrade everything.\n+\n[,sh]\n----\nsudo apt-get --yes full-upgrade\n----\n\n. Change to the project's root directory.\n+\n[,sh]\n----\ncd ~/Projects/pi-camera\n----\n\n. Set up the environment with `just init`.\nThis will install dependencies and initialize the virtual environment.\n+\n[,sh]\n----\njust init\n----\n\n. Reboot for the updated `/boot/firmware/config.txt` file to take effect.\n+\n[,sh]\n----\nsudo systemctl reboot\n----\n\n. Use `just run` to run the `camera.py` Python script inside the virtual environment.\n+\n[,sh]\n----\njust run\n----\n\n. Install and activate the systemd service with `just install`.\n+\n[,sh]\n----\njust install\n----\n\n=== Configure Screen Orientation\n\nOne of the things that may need tweaked is the screen orientation.\nThis 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.\nThe 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.\nIt is also described in the https://github.com/WayfireWM/wayfire-wiki/blob/master/Configuration.md[Configuration.md] file in the Wayfire repository.\nThe instructions here describe the basics necessary to rotate the screen.\n\n. Determine the available display outputs with the `kmsprint` command.\nHere, `DPI-1` corresponds to the HyperPixel 4.0.\n+\n[,sh]\n----\nkmsprint | grep Connector\nConnector 0 (32) HDMI-A-1 (disconnected)\nConnector 1 (42) HDMI-A-2 (disconnected)\nConnector 2 (48) DPI-1 (connected)\n----\n\n. Use `wlr-randr` to rotate the display.\nWhen running the command from an SSH connection, include the `WAYLAND_DISPLAY=wayland-1` variable as done here.\n+\n[,sh]\n----\nWAYLAND_DISPLAY=wayland-1 wlr-randr --output DPI-1 --transform 90\n----\n\n. To make the change permanent, configure the rotation in the Wayfire configuration file.\n+\n.~/.config/wayfire.ini\n[,ini]\n----\n[output:DPI-1]\ntransform = 90\n----\n\n== HDR\n\nThe Raspberry Pi Camera Module 3 supports HDR, but only at a lower resolution.\nHDR support has to toggled when `camera.py` isn't running.\n\n. Show the available V4L subdevices.\n+\n[,sh]\n----\nls /dev/v4l-subdev*\n/dev/v4l-subdev0  /dev/v4l-subdev1  /dev/v4l-subdev2  /dev/v4l-subdev3\n----\n\n. To enable HDR support for the Raspberry Pi Camera Module 3, use the following command on one of the V4L subdevices.\nIn my case, this ended up being `/dev/v4l-subdev2`.\n+\n[,sh]\n----\njust hdr /dev/v4l-subdev2\n----\n\n. To disable HDR support for the Raspberry Pi Camera Module 3, use this command with the corresponding V4L subdevice.\n+\n[,sh]\n----\njust hdr /dev/v4l-subdev2 disable\n----\n\n== Development\n\n. Run `just init-dev` to initialize the virtual environment for development.\nThis will install all of the necessary dependencies and the {pre-commit} hooks.\n+\n[,sh]\n----\njust init-dev\n----\n\n. Run the tests with https://docs.pytest.org/en/latest/[pytest] by running `just test`.\n+\n[,sh]\n----\njust test\n----\n\n. To update dependencies, run `just update`.\n+\n[,sh]\n----\njust update\n----\n\n. Use `just --list` to list other available tasks.\n+\n[,sh]\n----\njust --list\n----\n\n== todo\n\n* mypy\n* Make the camera application more robust.\nIt crashes really easily.\n* Incorporate some sort of power button to safely shutdown.\n* Add a NixOS configuration and build SD card images.\n\n== See Also\n\n* Jeff Geerling's https://github.com/geerlingguy/pi-camera[Raspberry Pi Camera]\n* https://github.com/Gordon999/RPiCamGUI[RPiCamGUI]\n* https://docs.circuitpython.org/projects/gps/en/latest/[Adafruit GPS Library Documentation]\n* https://github.com/raspberrypi/picamera2/blob/main/apps/app_full.py[picamera2 Full App]\n\n== Code of Conduct\n\nThe project's Code of Conduct is available in the link:CODE_OF_CONDUCT.adoc[Code of Conduct] file.\n\n== License\n\nThis repository is licensed under the https://www.gnu.org/licenses/gpl-3.0.html[GPLv3], available in the link:LICENSE.adoc[license file].\n\n© 2023-2024 Jordan Williams\n\n== Authors\n\nmailto:{email}[{author}]\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjwillikers%2Fpi-camera","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjwillikers%2Fpi-camera","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjwillikers%2Fpi-camera/lists"}