No description
Find a file
2026-07-12 17:42:46 -05:00
.cargo Add support for rpicam h264 stream mode 2026-07-12 17:41:22 -05:00
src Add support for rpicam h264 stream mode 2026-07-12 17:41:22 -05:00
test_images Add a testing system and a basic suite of test images 2023-12-28 14:45:44 -06:00
.env.dist The DiscordHandler now sends messages on detection 2023-12-30 13:38:38 -06:00
.gitignore Add output folder to gitignore 2026-07-12 17:42:46 -05:00
Cargo.lock Add embedded webserver via touche with endpoint to toggle detection 2024-01-01 21:49:17 -06:00
Cargo.toml Add support for rpicam h264 stream mode 2026-07-12 17:41:22 -05:00
crab-cam.png Add a testing system and a basic suite of test images 2023-12-28 14:45:44 -06:00
LICENSE Add LICENSE 2023-12-27 07:22:24 +00:00
README.md Add support for rpicam h264 stream mode 2026-07-12 17:41:22 -05:00
TODO.md Add embedded webserver via touche with endpoint to toggle detection 2024-01-01 21:49:17 -06:00

motion-camera

A CLI app intended to run on raspberry pi (or other other computer with a camera attached) and detect motion.

Features

  • Multiple strategies for motion detection
  • Record short video when motion is detected
  • Call configured webhooks when motion is detected
  • Support all common camera image formats

Building

You'll likely want to cross-compile this to aarch64 to run on the raspberry pi. To do this, you need to install the appropriate cross-compiler package for your system.

Debian:

$ sudo apt-get install gcc-aarch64-linux-gnu

Arch:

$ sudo pacman -S aarch64-linux-gnu-gcc

You'll also need to install the rust toolchain for the target architecture:

$ rustup target add aarch64-unknown-linux-gnu

Ensure the linker is specified correctly in .cargo/config

Build:

$ cargo build --release --target=aarch64-unknown-linux-gnu

Camera Backends

The default v4l backend captures YUYV frames from USB and other conventional V4L2 cameras. Select a device with:

$ ./motion-camera --backend v4l --cam /dev/video0

Raspberry Pi CSI cameras use libcamera instead of acting like conventional V4L2 capture devices. On Raspberry Pi OS, install the camera applications and verify that the camera is detected:

$ sudo apt install rpicam-apps
$ rpicam-hello --list-cameras

Then run motion-camera with the rpicam backend:

$ mkdir -p clips
$ ./motion-camera --backend rpicam --out-dir ./clips

This backend starts the system-provided rpicam-vid command and reads its raw YUV420 output. It captures 1280x720 video at 10 fps and downsamples the luma plane to 320x180 for motion detection. Recorded clips retain the full 1280x720 frames. Since libcamera remains outside the Rust binary, cross-compilation does not require Raspberry Pi libraries or a target sysroot.

The --cam option only applies to the v4l backend. The initial rpicam backend uses camera index 0.

For higher-quality clips without software H.264 encoding, install FFmpeg and use the rpicam-h264 backend:

$ sudo apt install rpicam-apps ffmpeg
$ mkdir -p clips
$ ./motion-camera --backend rpicam-h264 --out-dir ./clips

This backend asks rpicam-vid for a continuous 1920x1080, 30 fps, High-profile H.264 stream at 8 Mbps. It decodes one IDR frame every 500 ms for motion detection and writes the original encoded stream to clips without re-encoding. Completed raw clips are remuxed to MP4 by a background FFmpeg worker, so camera capture continues during finalization.

The H.264 backend retains approximately two seconds of encoded video before motion is detected. Clips therefore begin at an independently decodable IDR before the notification timestamp. The pre-roll buffer is also limited to 8 MiB for memory safety. Existing five-second motion expiry and 30-second maximum clip duration behavior still applies.

--interval values above 500 ms skip IDRs for detection while retaining all encoded frames. Values below 500 ms cannot make detection faster because the initial H.264 GOP is fixed at 15 frames.

FFmpeg is required only when --out-dir is used with rpicam-h264. If remuxing fails, the hidden raw .h264 file is retained in the output directory for diagnosis. Temporary raw and .part.mp4 files are removed after a successful remux.

To verify the raw frame layout expected by motion-camera, capture ten frames on the Pi:

$ rpicam-vid --camera 0 --nopreview --frames 10 --width 1280 --height 720 \
    --framerate 10 --codec yuv420 --flush --output test.yuv
$ stat -c '%s bytes' test.yuv

The expected size is 13824000 bytes (10 frames of 1,382,400 bytes each).

Testing

A suite of detection pair images can be found in ./test_images. They're sorted into directories. All of the image pairs in ./test_images/motion should trigger motion detection, while all of the pairs in ./test_images/no-motion should not trigger detection. There are test cases in the detect bundle which will run every image pair against every detection strategy.

Test for ./test_images/light-change are ignored, because some of the strategies cannot pass them.

One way to generate test images is to set environment variable MOTION_CAM_WRITE_DEBUG_IMAGES=true before running the program. When motion is detected, the pair of images that triggered detection will be saved to the current working directory. Set the similarity threshold very high to write a detection pair for frames without motion.

Detection Handlers

There is a DetectionHandler trait for generic detection handlers. Potential handlers could include:

  • webhook: multi-purpose
  • discord: send direct message
  • twilio: send text message
  • email: send email
  • cloud uploader: upload detection clip to cloud service

Discord

Set the environment variables:

  • MOTION_CAM_DISCORD_BOT_TOKEN Create a bot https://discord.com/developers/applications and get the token
  • MOTION_CAM_DICORD_DM_USER Currently needs to be the user ID who will recieve DMs when motion is detected. This user must be in at least one server with the bot. The bot will not send any messages in the server.

When both of these variables are set, the DiscordHandler will be registered.

Embedded Web Server

A webserver is hosted on port 4444 with an API endpoint at PUT /detecting. Send a boolean value (1, 0, true, false, etc) to turn motion detection on or off. This can be used to automate turning on detection when you leave your house for example.

In the future, this server may host a web UI to view or manage settings, and hopefully to view the live video stream eventually (via HLS or something similar).

Logging

This project uses env_logger with a default level of info. If you want to see debug logs then set RUST_LOG=debug, or just pass the -v flag.