WARNING: ahoy jippity
Timelapse Relay is a two-part, local-only timelapse system:
- Android sender: previews the camera and, when recording, sends JPEGs at two frames per second.
- Linux receiver: accepts those frames on the LAN, selects or merges them at a chosen interval, and writes durable video output incrementally.
It deliberately uses plain HTTP on a private network rather than Bluetooth or a cloud service. This is reliable over ordinary Wi-Fi, and works especially well with Android USB tethering: start tethering on the phone, then point the app at the Ubuntu machine's tether-interface address. Traffic never needs to leave the local link. Bluetooth is not used for media transport because it is slower and markedly less dependable for an always-on camera stream.
Requirements: Python 3.10+, ffmpeg, and Pillow.
sudo apt install ffmpeg python3-tk python3-pil
python3 linux_receiver/timelapse_receiver.py --output ~/Videos/timelapsesThe window shows the receiver URL (for example http://192.168.1.24:8765). Enter that URL in the Android app, tap Connect, then Start recording.
--interval is seconds per retained timelapse frame (default 1), --mode drop retains the newest frame in each interval, and --mode merge averages all frames in the interval. --playback-fps controls how quickly the resulting timelapse plays. Use --port to change the port.
Output is a session directory containing:
frames/: an atomically saved JPEG for every retained frame;segments/: a finalized H.264 MP4 segment for every retained frame;manifest.jsonl: append-only record of completed frames.
This intentionally favors recovery over file-count efficiency. A power loss or crash cannot invalidate earlier video; the active input frame is the only data that can be lost. To make one portable movie after recording, use the receiver's Export MP4 button (or --export SESSION_DIR), which creates an ffmpeg concat list and remuxes the already-encoded segments without re-encoding.
The receiver keeps at most one interval's worth of merged pixels in memory. At the default Android rate that is two frames per second; even a one-minute interval uses only a running pixel accumulator, not a growing frame queue.
Open android_sender in recent Android Studio and run it on a physical Android 8+ device. Grant Camera permission. The sender uses CameraX analysis with a monotonic 500 ms gate, JPEG-encodes one image at a time, and has a single-slot network queue: if the network falls behind, it drops the stale frame instead of accumulating memory.
For a USB-only setup, enable Android's USB tethering, find the Ubuntu USB network address shown by the receiver, and use that address in the app. For Wi-Fi, put both devices on the same Wi-Fi and use the displayed receiver URL. The receiver binds to all interfaces but only accepts requests from the connected network; do not expose its port to the public internet.