{"id":95,"date":"2025-09-02T14:25:08","date_gmt":"2025-09-02T14:25:08","guid":{"rendered":"https:\/\/scootercam.net\/notes\/?p=95"},"modified":"2025-09-02T14:25:08","modified_gmt":"2025-09-02T14:25:08","slug":"scootercams-sunsets","status":"publish","type":"post","link":"https:\/\/scootercam.net\/blog\/scootercams-sunsets\/","title":{"rendered":"Scootercam&#8217;s Sunsets"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\">Dual Camera Timelapse System<\/h1>\n\n\n\n<p>An automated timelapse capture system for Amcrest and Reolink IP cameras running on Raspberry Pi. Captures images from both cameras simultaneously, processes them into MP4 videos, and uploads to an FTP server.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Features<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Concurrent Image Capture<\/strong>: Captures from both Amcrest and Reolink cameras with a 2-second offset<\/li>\n\n\n\n<li><strong>Automated Processing<\/strong>: Creates MP4 timelapses from captured images using ffmpeg<\/li>\n\n\n\n<li><strong>Staggered Upload<\/strong>: Uploads videos with timing offsets to prevent bandwidth conflicts<\/li>\n\n\n\n<li><strong>Error Handling<\/strong>: Comprehensive logging, connectivity checks, and failure recovery<\/li>\n\n\n\n<li><strong>Resource Management<\/strong>: Disk space monitoring and automatic cleanup of temporary files<\/li>\n\n\n\n<li><strong>Quality Control<\/strong>: Automatically removes corrupt\/small image files<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Hardware Requirements<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Raspberry Pi (tested on Pi 5)<\/li>\n\n\n\n<li>Network access to both cameras<\/li>\n\n\n\n<li>Sufficient storage space (minimum 1GB free recommended)<\/li>\n\n\n\n<li>Internet connection for FTP uploads<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Software Dependencies<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>wget<\/code> &#8211; for camera image capture<\/li>\n\n\n\n<li><code>ffmpeg<\/code> &#8211; for video processing<\/li>\n\n\n\n<li><code>curl<\/code> &#8211; for FTP uploads<\/li>\n\n\n\n<li><code>ping<\/code> &#8211; for connectivity checks<\/li>\n\n\n\n<li>Standard Unix utilities (<code>find<\/code>, <code>mv<\/code>, <code>rm<\/code>, etc.)<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Installation<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Clone or download the script<\/strong> to your Raspberry Pi<\/li>\n\n\n\n<li><strong>Make it executable<\/strong>: <code>chmod +x dual-camera-timelapse.sh<\/code><\/li>\n\n\n\n<li><strong>Install dependencies<\/strong> (if not already present): <code>sudo apt update sudo apt install wget ffmpeg curl<\/code><\/li>\n\n\n\n<li><strong>Create required directories<\/strong>: <code>sudo mkdir -p \/var\/www\/html\/{sa,ss,sawork,swork,mp} sudo chown -R $USER:$USER \/var\/www\/html\/<\/code><\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Configuration<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Camera Settings<\/h3>\n\n\n\n<p>Edit the script and update these variables with your camera details:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Amcrest Camera\nAMCREST_USER=\"admin\"\nAMCREST_PASS=\"your_password\"\nAMCREST_IP=\"192.168.1.205\"\n\n# Reolink Camera  \nREOLINK_USER=\"admin\"\nREOLINK_PASS=\"your_password\"\nREOLINK_IP=\"192.168.1.211\"\nREOLINK_RS=\"your_rs_token\"  # Found in Reolink camera API settings\n\n# FTP Upload\nFTP_USER=\"your_ftp_user\"\nFTP_PASS=\"your_ftp_password\"\nFTP_HOST=\"your_ftp_server\"\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Security Best Practices<\/h3>\n\n\n\n<p><strong>Option 1: Environment Variables<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export AMCREST_PASS=\"your_password\"\nexport REOLINK_PASS=\"your_password\" \nexport FTP_PASS=\"your_ftp_password\"\n<\/code><\/pre>\n\n\n\n<p><strong>Option 2: Config File<\/strong> (Recommended)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Create \/home\/pi\/.camera-config\nAMCREST_PASS=\"your_password\"\nREOLINK_PASS=\"your_password\"\nFTP_PASS=\"your_ftp_password\"\n\n# Source in script:\nsource \/home\/pi\/.camera-config\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Capture Settings<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Amcrest<\/strong>: 480 images (32 minutes at 4-second intervals)<\/li>\n\n\n\n<li><strong>Reolink<\/strong>: 600 images (40 minutes at 4-second intervals)<\/li>\n\n\n\n<li><strong>Offset<\/strong>: 2-second delay between camera starts<\/li>\n\n\n\n<li><strong>Output<\/strong>: 24fps MP4 videos, 1280&#215;720 resolution<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Usage<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Manual Execution<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>.\/dual-camera-timelapse.sh\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Automated Execution (Cron)<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># Edit crontab\ncrontab -e\n\n# Add entry (runs every 2 hours):\n0 *\/2 * * * \/home\/pi\/dual-camera-timelapse.sh\n\n# Or daily at 6 AM:\n0 6 * * * \/home\/pi\/dual-camera-timelapse.sh\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Systemd Service (Optional)<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># Create service file\nsudo nano \/etc\/systemd\/system\/dual-timelapse.service\n\n# Enable and start\nsudo systemctl enable dual-timelapse.service\nsudo systemctl start dual-timelapse.service\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">File Structure<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>\/var\/www\/html\/\n\u251c\u2500\u2500 sa\/           # Amcrest raw images\n\u251c\u2500\u2500 ss\/           # Reolink raw images  \n\u251c\u2500\u2500 sawork\/       # Amcrest processed images\n\u251c\u2500\u2500 swork\/        # Reolink processed images\n\u2514\u2500\u2500 mp\/           # Final MP4 videos\n    \u251c\u2500\u2500 sa2024-01-15.mp4  # Amcrest timelapse\n    \u2514\u2500\u2500 ss2024-01-15.mp4  # Reolink timelapse\n\n\/home\/pi\/\n\u2514\u2500\u2500 dual-timelapse.log    # System logs\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Monitoring &amp; Logs<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">View Real-time Logs<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>tail -f \/home\/pi\/dual-timelapse.log\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Check System Status<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># Process status\nps aux | grep timelapse\n\n# Disk usage\ndf -h \/var\/www\/html\n\n# Recent log entries\ntail -20 \/home\/pi\/dual-timelapse.log\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Troubleshooting<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Common Issues<\/h3>\n\n\n\n<p><strong>Camera Unreachable<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Check IP addresses and network connectivity<\/li>\n\n\n\n<li>Verify camera web interfaces are accessible<\/li>\n\n\n\n<li>Ensure cameras are powered on<\/li>\n<\/ul>\n\n\n\n<p><strong>Permission Denied Errors<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Fix directory permissions\nsudo chown -R $USER:$USER \/var\/www\/html\/\nsudo chmod -R 755 \/var\/www\/html\/\n<\/code><\/pre>\n\n\n\n<p><strong>Low Quality\/Missing Images<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Check camera settings and image quality<\/li>\n\n\n\n<li>Verify network stability<\/li>\n\n\n\n<li>Monitor disk space usage<\/li>\n<\/ul>\n\n\n\n<p><strong>ffmpeg Failures<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Test ffmpeg manually\nffmpeg -framerate 24 -pattern_type glob -i '\/var\/www\/html\/sawork\/*.jpg' \\\n       -c:v libx264 test.mp4\n<\/code><\/pre>\n\n\n\n<p><strong>FTP Upload Issues<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Verify FTP credentials and server accessibility<\/li>\n\n\n\n<li>Check network connectivity to FTP server<\/li>\n\n\n\n<li>Test manual upload: <code>curl -T test.mp4 ftp:\/\/server\/ --user user:pass<\/code><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Log Analysis<\/h3>\n\n\n\n<p><strong>Check for specific errors<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>grep \"ERROR\" \/home\/pi\/dual-timelapse.log\ngrep \"WARNING\" \/home\/pi\/dual-timelapse.log\n<\/code><\/pre>\n\n\n\n<p><strong>Monitor capture success rate<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>grep \"capture completed\" \/home\/pi\/dual-timelapse.log\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Customization<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Adjust Capture Duration<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># In the script, modify these lines:\nfor run in {1..480}; do    # Amcrest (32 min)\nfor run in {1..600}; do    # Reolink (40 min)\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Change Video Quality<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># Higher quality (larger files):\n-crf 20\n\n# Lower quality (smaller files):  \n-crf 30\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Different Frame Rates<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># Slower motion:\n-framerate 12\n\n# Faster motion:\n-framerate 30\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Advanced Configuration<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Multiple Intervals Per Day<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># Capture every 4 hours\n0 *\/4 * * * \/home\/pi\/dual-camera-timelapse.sh\n\n# Capture only during daylight (6 AM to 6 PM)\n0 6,10,14,18 * * * \/home\/pi\/dual-camera-timelapse.sh\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Storage Management<\/h3>\n\n\n\n<p>The script automatically:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Removes images smaller than 10KB (corrupt\/failed captures)<\/li>\n\n\n\n<li>Cleans up temporary files after processing<\/li>\n\n\n\n<li>Can be extended to remove old videos after X days<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Network Optimization<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>2-second camera offset reduces network congestion<\/li>\n\n\n\n<li>30-second upload stagger prevents FTP server overload<\/li>\n\n\n\n<li>5-second processing delay prevents CPU\/disk conflicts<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Camera API References<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Amcrest API<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>http:&#47;&#47;IP\/cgi-bin\/snapshot.cgi?channel=1&amp;type=0\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Reolink API<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>http:&#47;&#47;IP\/cgi-bin\/api.cgi?cmd=Snap&amp;channel=0&amp;rs=TOKEN&amp;user=USER&amp;password=PASS\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Performance Notes<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Total execution time<\/strong>: ~45-50 minutes<\/li>\n\n\n\n<li><strong>Peak disk usage<\/strong>: ~2-4GB during processing<\/li>\n\n\n\n<li><strong>Network bandwidth<\/strong>: Dependent on image resolution and upload speeds<\/li>\n\n\n\n<li><strong>CPU usage<\/strong>: High during ffmpeg processing phases<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Support<\/h2>\n\n\n\n<p>Check logs first for troubleshooting, then verify:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Camera connectivity and credentials<\/li>\n\n\n\n<li>Disk space availability<\/li>\n\n\n\n<li>Network stability<\/li>\n\n\n\n<li>FTP server accessibility<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Version History<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>v1.0 &#8211; Initial dual camera implementation<\/li>\n\n\n\n<li>Added concurrent capture with staggered processing<\/li>\n\n\n\n<li>Comprehensive error handling and logging<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Dual Camera Timelapse System An automated timelapse capture system for Amcrest and Reolink IP cameras running on Raspberry Pi. Captures images from both cameras simultaneously, processes them into MP4 videos, and uploads to an FTP server. Features Hardware Requirements Software Dependencies Installation Configuration Camera Settings Edit the script and update these variables with your camera &#8230; <a title=\"Scootercam&#8217;s Sunsets\" class=\"read-more\" href=\"https:\/\/scootercam.net\/blog\/scootercams-sunsets\/\" aria-label=\"Read more about Scootercam&#8217;s Sunsets\">Read more<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[8],"tags":[],"class_list":["post-95","post","type-post","status-publish","format-standard","hentry","category-raspberry-pi"],"_links":{"self":[{"href":"https:\/\/scootercam.net\/blog\/wp-json\/wp\/v2\/posts\/95","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/scootercam.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/scootercam.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/scootercam.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/scootercam.net\/blog\/wp-json\/wp\/v2\/comments?post=95"}],"version-history":[{"count":1,"href":"https:\/\/scootercam.net\/blog\/wp-json\/wp\/v2\/posts\/95\/revisions"}],"predecessor-version":[{"id":96,"href":"https:\/\/scootercam.net\/blog\/wp-json\/wp\/v2\/posts\/95\/revisions\/96"}],"wp:attachment":[{"href":"https:\/\/scootercam.net\/blog\/wp-json\/wp\/v2\/media?parent=95"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/scootercam.net\/blog\/wp-json\/wp\/v2\/categories?post=95"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/scootercam.net\/blog\/wp-json\/wp\/v2\/tags?post=95"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}