There have been several iterations of this system but the idea hasn’t much changed – a camera swings towards the setting sun and captures images, then produces a timelapse video of the sunset. In this version an image is captures every five seconds from 20 minutes before until 20 minutes after sunset. The issue came when I added a second camera to the mix and expected a tiny Raspberry Pi to handle taking two images from two cameras at the exact same time, and doing that 600 times over. Things needed to stagger.ScooterCam Sunset System – Project Summary
Overview
A complete automated sunset timelapse capture, compilation, and upload system for dual IP cameras (Amcrest and Reolink) on Lake Michigan’s eastern shore. Built for Raspberry Pi 5 with SSD storage.
Workflow Timeline
15:00 - Sunset at 17:30
|
16:00 - Cron job starts sunset_master.py
|
17:10 - Capture window begins (sunset - 20 min)
| ├─ capture_amcrest.py starts
| └─ capture_reolink.py starts 2.5 seconds later
|
| [Both cameras capture 1 image every 5 seconds]
| [~480 images per camera over 40 minutes]
|
17:50 - Capture window ends (sunset + 20 min)
| └─ ~80 images per camera captured
|
17:50 - Amcrest processing begins
| ├─ compile_video.py creates MP4
| ├─ Identifies poster image (closest to 17:30)
| └─ upload_ftp.py sends to server
|
17:55 - 5-minute delay (stagger compilation)
|
17:55 - Reolink processing begins
| ├─ compile_video.py creates MP4
| ├─ Identifies poster image
| └─ upload_ftp.py sends to server
|
18:00 - Process complete
Component Details
1. sunset_calculator.py
Purpose: Calculate daily sunset times and capture windows
Features:
- Uses Astral library for astronomical calculations
- America/Detroit timezone aware
- Configurable location coordinates
- Provides 40-minute capture window (±20 min from civil sunset)
Key Functions:
get_sunset_times()– Returns today’s sunset and capture windowshould_capture_now()– Checks if current time is in capture window
2. capture_amcrest.py & capture_reolink.py
Purpose: Download images from cameras during sunset window
Features:
- Waits automatically until capture start time
- Downloads snapshot every 30 seconds
- Error handling with retries
- Creates organized storage structure
- Validates downloaded files
- Logs success/failure of each capture
Output:
- Images:
/mnt/ssd/sunset_captures/YYYY-MM-DD/[camera]/camerane_YYYYMMDD_HHMMSS.jpg
3. compile_video.py
Purpose: Convert captured images into MP4 timelapse videos
Features:
- Uses ffmpeg for video compilation
- 30 fps output, H.264 codec
- CRF 23 quality (configurable)
- Identifies poster image (closest to actual sunset)
- Creates both video and poster image
- Error handling and validation
Output:
- Video:
sunset_[camera]_YYYY-MM-DD.mp4 - Poster:
sunset_[camera]_YYYY-MM-DD_poster.jpg
4. upload_ftp.py
Purpose: Upload compiled videos and posters to Glowhost
Features:
- Secure FTP connection
- Separate directories for videos (/sw) and images (/sr)
- Connection testing mode (–test flag)
- Retry logic for failed uploads
- Upload progress reporting
- Validates successful transfer
Configuration:
- Host: scootercam.net
- User: sunsets@scootercam.net
- Videos → /sw directory
- Images → /sr directory
5. sunset_master.py
Purpose: Orchestrate the complete workflow
Features:
- Coordinates all components
- Runs both camera captures simultaneously
- Staggers video compilation (5-min delay)
- Comprehensive logging
- Error tracking and reporting
- Final summary of all operations
Workflow:
- Calculate sunset time
- Launch both capture scripts in parallel
- Wait for captures to complete
- Compile and upload Amcrest
- Wait 5 minutes
- Compile and upload Reolink
- Generate summary report
6. system_check.py
Purpose: Verify system configuration before first run
Checks:
- System commands (ffmpeg, wget, python3)
- Python packages (astral, pytz)
- Required scripts present
- Storage directories exist and writable
- Camera connectivity
- FTP connection
- Sunset calculator functionality
7. setup.sh
Purpose: Automated installation script
Actions:
- Installs system dependencies
- Installs Python packages
- Creates project directory
- Sets up storage directories
- Makes scripts executable
- Optionally configures cron job
- Runs system check
File Organization
Local Storage Structure
/mnt/ssd/
├── sunset_captures/
│ └── 2025-11-11/
│ ├── amcrest/
│ │ ├── amcrest_20251111_171000.jpg
│ │ ├── amcrest_20251111_171005.jpg
│ │ ├── amcrest_20251111_171010.jpg
│ │ └── ... (~480 images)
│ └── reolink/
│ ├── reolink_20251111_171002.jpg (staggered 2.5s)
│ ├── reolink_20251111_171007.jpg
│ └── ... (~480 images)
└── sunset_videos/
└── 2025-11-11/
├── sunset_amcrest_2025-11-11.mp4
├── sunset_amcrest_2025-11-11_poster.jpg
├── sunset_reolink_2025-11-11.mp4
└── sunset_reolink_2025-11-11_poster.jpg
Remote Storage Structure
scootercam.net/
├── sw/ (videos)
│ ├── sunset_amcrest_2025-11-11.mp4
│ └── sunset_reolink_2025-11-11.mp4
└── sr/ (images)
├── sunset_amcrest_2025-11-11_poster.jpg
└── sunset_reolink_2025-11-11_poster.jpg
Technical Specifications
Video Settings
- Codec: H.264 (libx264)
- Frame Rate: 30 fps
- Quality: CRF 23
- Preset: medium
- Pixel Format: yuv420p (universal compatibility)
- Typical Size: 10-50 MB per video
Image Capture
- Interval: 5 seconds
- Duration: 40 minutes
- Images per camera: ~480 (8 images per minute × 40 minutes)
- Format: JPEG
- Source Resolution: Native camera resolution
- Stagger: Reolink starts 2.5 seconds after Amcrest to avoid simultaneous network load
Network Requirements
- Local Network: Access to 192.168.1.x cameras
- Internet: FTP upload to scootercam.net
- Bandwidth: ~50-100 MB upload per day
Storage Requirements
- Daily Capture: ~800 MB – 1.2 GB (images + videos)
- ~480 images per camera at ~500 KB each = ~240 MB per camera
- Videos after compression: ~50-100 MB per camera
- Monthly: ~25-35 GB
- Recommended: 128+ GB SSD
- Retention: Configure cleanup as needed
Dependencies
System Packages
- python3 (3.9+)
- ffmpeg
- wget
- ftp (optional, for manual testing)
Python Packages
- astral==3.2 (astronomical calculations)
- pytz==2024.1 (timezone support)
Automation
Cron Configuration
cron
# Daily execution at 4:00 PM
0 16 * * * cd /home/pi/scootercam-sunset && /usr/bin/python3 sunset_master.py >> /var/log/scootercam-sunset.log 2>&1
Log Management
- Location:
/var/log/scootercam-sunset.log - Rotation: Implement logrotate if desired
- Monitoring: Use
tail -ffor real-time viewing
Maintenance
Daily
- System runs automatically via cron
- Check logs for errors if needed
Weekly
- Review log files
- Verify uploads to server
- Check storage space
Monthly
- Clean up old captures
- Verify camera connectivity
- Review system performance
Seasonal
- Update coordinates if needed
- Adjust for significant camera repositioning
- Test system before DST changes (auto-adjusts)
Error Handling
Capture Failures
- Individual image failures logged but don’t stop process
- Retries on timeout (3 attempts)
- Continues even if some images fail
Compilation Failures
- Logged with detailed error messages
- Doesn’t stop other camera’s processing
- Can be re-run manually for specific dates
Upload Failures
- Logged with connection details
- Can be re-uploaded manually
- FTP test mode available for diagnostics
Recovery
All components support manual execution:
- Capture: Can be re-run for current day
- Compile: Can be run for any past date with images
- Upload: Can be run for any past date with videos
Performance Considerations
Resource Usage
- CPU: Moderate during compilation
- RAM: Low (<500 MB)
- Disk I/O: Moderate during capture
- Network: Low (periodic small uploads)
Optimization
- 5-minute stagger prevents resource contention
- Parallel captures maximize efficiency
- H.264 preset ‘medium’ balances speed/quality
Scalability
- Can add more cameras by duplicating capture scripts
- Stagger compilation by additional 5-minute intervals
- Storage scales linearly with retention period
Security Considerations
Credentials
- Camera passwords in scripts (local system only)
- FTP credentials in scripts (consider encryption for production)
- File permissions set appropriately
Network
- Cameras on local network only
- FTP upload over internet (consider FTPS)
- No incoming connections required
Recommendations
- Keep Pi system updated
- Use strong camera passwords
- Consider VPN for remote access
- Regular backup of scripts
Future Enhancements
Potential Features
- Web interface for monitoring
- SMS/email notifications on failures
- Cloud storage integration
- Machine learning sunset quality prediction
- Multi-day compilation
- Weather data overlay
- Social media auto-posting
System Improvements
- Database logging
- Grafana dashboard
- Automated cleanup policies
- Redundant storage
- FTPS support
- Configuration file (vs. hardcoded)
Documentation Files
- README.md – Complete system documentation
- INSTALL.md – Installation instructions
- QUICK_REFERENCE.md – Command reference
- PROJECT_SUMMARY.md – This file
- requirements.txt – Python dependencies
Support and Troubleshooting
System Check
bash
python3 system_check.py
Manual Testing
bash
# Test camera
python3 capture_amcrest.py
# Test compilation
python3 compile_video.py amcrest
# Test upload
python3 upload_ftp.py --test
Logs
bash
tail -f /var/log/scootercam-sunset.log
Project Stats
- Scripts: 7 Python files
- Total Lines: ~1,500
- Documentation: 5 markdown files
- Setup Time: ~15 minutes
- Daily Runtime: ~60 minutes
- Storage per Day: ~200 MB
Built for Scootercam.net – Capturing Lake Michigan sunsets since 2016 🌅