{"id":1101,"date":"2026-02-02T12:50:54","date_gmt":"2026-02-02T17:50:54","guid":{"rendered":"https:\/\/scootercam.net\/blog\/?p=1101"},"modified":"2026-02-02T12:50:55","modified_gmt":"2026-02-02T17:50:55","slug":"scootercam-3","status":"publish","type":"post","link":"https:\/\/scootercam.net\/blog\/scootercam-3\/","title":{"rendered":"Scootercam 3"},"content":{"rendered":"\n<p>We replaced the beach deck camera with a Reolink Track Mix, a pan-tilt camera with 2 lenses (wide-angle and telephoto). <\/p>\n\n\n\n<p>Our original beach deck camera became invisible on the new home network.The wide-angle PanoramaScootercam gives us 5 views, so we used it to fill the gap. To fully deploy the new camera and temporarily disable the wide view, we&#8217;re making changes to the config,yaml file on the Raspberry Pi. This is that, outlined by Claude AI:<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">TrackMix Migration Checklist<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Transitioning from Duo 3 to TrackMix as Primary Camera<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Pre-Deployment: TrackMix Camera Setup<\/h3>\n\n\n\n<p>Before deploying the new config.yaml, configure these settings in the TrackMix web interface:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">1. Verify Network Settings<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>[ ] IP Address: 192.168.40.236 (confirmed)<\/li>\n\n\n\n<li>[ ] Port: 80<\/li>\n\n\n\n<li>[ ] Username: admin<\/li>\n\n\n\n<li>[ ] Password: SecretPassword<\/li>\n\n\n\n<li>[ ] Ping test from Pi: <code>ping 192.168.40.236<\/code><\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">2. Configure Preset Positions<\/h4>\n\n\n\n<p>Access the TrackMix web interface and set up 5 presets (0-4): <\/p>\n\n\n\n<p><strong>Recommended Setup:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>[ ] <strong>Preset 0<\/strong>: Home\/Default position (north or northeast &#8211; your primary view)<\/li>\n\n\n\n<li>[ ] <strong>Preset 1<\/strong>: South view (night sky, dawn colors)<\/li>\n\n\n\n<li>[ ] <strong>Preset 2<\/strong>: Southwest view (morning shots)<\/li>\n\n\n\n<li>[ ] <strong>Preset 3<\/strong>: West view (CRITICAL &#8211; this is your sunset position for winter)<\/li>\n\n\n\n<li>[ ] <strong>Preset 4<\/strong>: Northwest view (sunset position for summer)<\/li>\n<\/ul>\n\n\n\n<p><strong>To set presets:<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Log into TrackMix web interface<\/li>\n\n\n\n<li>Go to Settings \u2192 PTZ Settings \u2192 Preset Points<\/li>\n\n\n\n<li>Manually position camera to desired view<\/li>\n\n\n\n<li>Click &#8220;Set&#8221; for preset number<\/li>\n\n\n\n<li>Give it a descriptive name<\/li>\n\n\n\n<li>Test each preset by clicking &#8220;Call&#8221;<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">3. Verify Stream Settings<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>[ ] Wide lens (Channel 0) &#8211; Main stream set to 3840&#215;2160 @ 25fps<\/li>\n\n\n\n<li>[ ] Wide lens (Channel 0) &#8211; Sub stream set to 640&#215;480 (for previews)<\/li>\n\n\n\n<li>[ ] Telephoto lens (Channel 1) &#8211; Main stream set to 3840&#215;2160 @ 25fps<\/li>\n\n\n\n<li>[ ] Both streams using H.264 codec<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">4. Check Camera Time &amp; Timezone<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>[ ] Camera timezone set to America\/Detroit<\/li>\n\n\n\n<li>[ ] Time synchronized (NTP enabled)<\/li>\n\n\n\n<li>[ ] Date\/time matches Pi time<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Deployment Steps<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Step 1: Backup Current Configuration<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>cd \/home\/pi\/camctl\ncp config.yaml config.yaml.backup.$(date +%Y%m%d_%H%M%S)\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Step 2: Stop Services<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Stop the controller service\nsudo systemctl stop scootercam-controller.service\n\n# Verify it's stopped\nsudo systemctl status scootercam-controller.service\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Step 3: Deploy New Configuration<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Copy new config.yaml to camctl directory\n# (Upload via your preferred method - FTP, SCP, or manual edit)\n\n# Verify the file\ncat \/home\/pi\/camctl\/config.yaml | head -20\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Step 4: Test Configuration Syntax<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>cd \/home\/pi\/camctl\n\n# Test YAML syntax (if you have PyYAML installed)\npython3 -c \"import yaml; yaml.safe_load(open('config.yaml'))\"\n\n# Should return nothing if successful\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Step 5: Test Camera Connectivity<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Test if Python can reach the TrackMix\npython3 &lt;&lt; EOF\nfrom lib.camera_controller import CameraController\nimport yaml\n\nconfig = yaml.safe_load(open('config.yaml'))\ncam = CameraController(config&#91;'cameras']&#91;'ptz'])\nprint(\"Camera reachable:\", cam.test_connection())\nEOF\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Step 6: Start Services<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Start the controller service\nsudo systemctl start scootercam-controller.service\n\n# Watch the logs for errors\ntail -f \/home\/pi\/camctl\/scootercam.log\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Post-Deployment Testing<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Test 1: Manual Snapshot Capture (Critical!)<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>cd \/home\/pi\/camctl\n\n# Test PTZ snapshot\npython3 -c \"\nfrom lib.camera_controller import CameraController\nimport yaml\n\nconfig = yaml.safe_load(open('config.yaml'))\nptz = CameraController(config&#91;'cameras']&#91;'ptz'])\n\n# Move to preset 0 and capture\nptz.move_to_preset(0)\nimport time; time.sleep(3)\nimg = ptz.capture_snapshot()\nif img:\n    print('\u2713 PTZ snapshot successful')\nelse:\n    print('\u2717 PTZ snapshot FAILED')\n\"\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Test 2: Verify Frame Capture for Timelapse<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Check that frames are being captured\nls -lth \/home\/pi\/camctl\/data\/timelapse_frames\/ | head -10\n\n# Should see files named like: ptz_20260202_143000.jpg\n\n# Watch for new frames (should appear every 10 seconds)\nwatch -n 5 'ls -lth \/home\/pi\/camctl\/data\/timelapse_frames\/ | head -5'\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Test 3: Check Preset Movement<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Test that presets work\npython3 &lt;&lt; EOF\nfrom lib.camera_controller import CameraController\nimport yaml\nimport time\n\nconfig = yaml.safe_load(open('config.yaml'))\nptz = CameraController(config&#91;'cameras']&#91;'ptz'])\n\nprint(\"Testing presets...\")\nfor preset in &#91;0, 1, 2, 3, 4, 0]:\n    print(f\"Moving to preset {preset}\")\n    ptz.move_to_preset(preset)\n    time.sleep(5)\nprint(\"\u2713 Preset test complete\")\nEOF\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Test 4: Verify FTP Uploads<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Check upload logs\ngrep \"Uploaded\" \/home\/pi\/camctl\/scootercam.log | tail -10\n\n# Should see entries like:\n# Uploaded ptz_snapshot.jpg to \/cameras\/\n# Uploaded ptz_snapshot.webp to \/cameras\/\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Test 5: Check Website Display<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>[ ] Visit ScooterCam.net<\/li>\n\n\n\n<li>[ ] Verify snapshot images are from TrackMix (not Duo 3)<\/li>\n\n\n\n<li>[ ] Check image timestamp matches current time<\/li>\n\n\n\n<li>[ ] Verify multiple sizes loaded (1440, 800, 400)<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Test 6: Monitor Rolling Timelapse (20 min wait)<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Wait for first compilation (occurs every 20 minutes)\n# Check for compiled video\nls -lth \/home\/pi\/camctl\/static\/timelapse\/ | grep rolling\n\n# Should see: ptz_rolling_4hr_20260202_1440.mp4\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Monitoring &amp; Verification<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Watch System Status<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Monitor logs in real-time\ntail -f \/home\/pi\/camctl\/scootercam.log\n\n# Filter for errors\ntail -f \/home\/pi\/camctl\/scootercam.log | grep -i error\n\n# Filter for PTZ activity\ntail -f \/home\/pi\/camctl\/scootercam.log | grep -i ptz\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Check Disk Usage<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>df -h \/home\/pi\/camctl\n# Should stay below 80%\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Verify Duo 3 is Disabled<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Check that REO is not uploading\ngrep \"reo\" \/home\/pi\/camctl\/scootercam.log | tail -20\n# Should show \"disabled\" or no recent activity\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Sunset Timelapse Testing (Wait for Sunset!)<\/h3>\n\n\n\n<p><strong>Automatic Test:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>[ ] System should automatically start sunset capture ~20 min before sunset<\/li>\n\n\n\n<li>[ ] Camera should move to preset 3 (winter) or 4 (summer)<\/li>\n\n\n\n<li>[ ] Frames captured every 3 seconds<\/li>\n\n\n\n<li>[ ] Continues for ~20 minutes after sunset<\/li>\n\n\n\n<li>[ ] Camera returns to preset 0 after completion<\/li>\n<\/ul>\n\n\n\n<p><strong>Check Results:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># After sunset, check for sunset frames\nls -lth \/home\/pi\/camctl\/data\/timelapse_frames\/ | grep sunset\n\n# Check for compiled sunset video\nls -lth \/home\/pi\/camctl\/static\/timelapse\/ | grep sunset\n\n# Should see: ptz_sunset_20260202.mp4\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Troubleshooting<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Problem: Camera not responding<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Ping test\nping 192.168.40.236\n\n# Check camera web interface (from browser)\nhttp:&#47;&#47;192.168.40.236\n\n# Verify credentials in config.yaml\ngrep -A 5 \"ptz:\" \/home\/pi\/camctl\/config.yaml\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Problem: Presets not working<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Check preset configuration in camera web interface<\/li>\n\n\n\n<li>Verify preset numbers 0-4 are defined<\/li>\n\n\n\n<li>Test manually in camera web UI first<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Problem: No frames being captured<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Check frame directory exists\nls -ld \/home\/pi\/camctl\/data\/timelapse_frames\/\n\n# Check permissions\nls -l \/home\/pi\/camctl\/data\/\n\n# Check logs for errors\ngrep -i \"frame\" \/home\/pi\/camctl\/scootercam.log | tail -20\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Problem: Wrong channel\/stream<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Verify channel: 0 in config (wide lens)<\/li>\n\n\n\n<li>Check stream: &#8220;main&#8221; in config (full quality)<\/li>\n\n\n\n<li>Test with channel: 1 if you want telephoto view<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Problem: FTP uploads failing<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Test FTP manually\nftp 23.229.41.82\n# user: pi_in@scootercam.net\n# pass: BeachGlassPi_In\n\n# Check upload logs\ngrep -i \"ftp\\|upload\" \/home\/pi\/camctl\/scootercam.log | tail -30\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Rollback Procedure (If Needed)<\/h3>\n\n\n\n<p>If something goes wrong:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Stop service\nsudo systemctl stop scootercam-controller.service\n\n# Restore backup\ncd \/home\/pi\/camctl\ncp config.yaml.backup.YYYYMMDD_HHMMSS config.yaml\n\n# Restart service\nsudo systemctl start scootercam-controller.service\n\n# Verify restored\ngrep \"name:\" config.yaml\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Success Criteria<\/h3>\n\n\n\n<p>After 24 hours of operation, verify:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>[X] PTZ snapshots uploading every 10 minutes<\/li>\n\n\n\n<li>[X] Rolling 4-hour timelapse compiling every 20 minutes<\/li>\n\n\n\n<li>[X] Sunset timelapse captured and compiled<\/li>\n\n\n\n<li>[X] No errors in logs<\/li>\n\n\n\n<li>[X] Disk usage stable (not growing uncontrollably)<\/li>\n\n\n\n<li>[X] REO\/Duo 3 not uploading<\/li>\n\n\n\n<li>[X] Website showing PTZ images<\/li>\n\n\n\n<li>[X] Health monitoring email received at 8 AM<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Re-enabling Duo 3 (Future)<\/h3>\n\n\n\n<p>When ready to re-enable the Duo 3:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Edit config.yaml: <code>cameras: reo: enabled: true capture_coordination: cameras: reo: enabled: true<\/code><\/li>\n\n\n\n<li>Restart service<\/li>\n\n\n\n<li>Verify both cameras operating without conflicts<\/li>\n\n\n\n<li>Monitor timing &#8211; PTZ at :00, :10, :20&#8230; \/ REO at :05, :15, :25&#8230;<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Notes<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Keep config.yaml.backup files for at least 7 days<\/li>\n\n\n\n<li>Document any preset position changes<\/li>\n\n\n\n<li>If you change presets in camera UI, update config.yaml comments<\/li>\n\n\n\n<li>Monitor first sunset timelapse carefully &#8211; this is the showpiece!<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Questions to Address<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Do you want wide or telephoto for sunset?<\/strong>\n<ul class=\"wp-block-list\">\n<li>Wide (channel: 0) = full horizon context<\/li>\n\n\n\n<li>Telephoto (channel: 1) = zoomed sunset detail<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Should rolling timelapse use multiple views?<\/strong>\n<ul class=\"wp-block-list\">\n<li>Current config rotates through presets during day<\/li>\n\n\n\n<li>Alternative: stick to one view for consistency<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Live video stream selection?<\/strong>\n<ul class=\"wp-block-list\">\n<li>Currently set to wide (channel 0, main stream)<\/li>\n\n\n\n<li>Could use telephoto for detail shots<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p>Let me know if any issues arise during deployment!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>We replaced the beach deck camera with a Reolink Track Mix, a pan-tilt camera with 2 lenses (wide-angle and telephoto). Our original beach deck camera became invisible on the new home network.The wide-angle PanoramaScootercam gives us 5 views, so we used it to fill the gap. To fully deploy the new camera and temporarily disable &#8230; <a title=\"Scootercam 3\" class=\"read-more\" href=\"https:\/\/scootercam.net\/blog\/scootercam-3\/\" aria-label=\"Read more about Scootercam 3\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","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":[46],"tags":[],"class_list":["post-1101","post","type-post","status-publish","format-standard","hentry","category-blog"],"_links":{"self":[{"href":"https:\/\/scootercam.net\/blog\/wp-json\/wp\/v2\/posts\/1101","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\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/scootercam.net\/blog\/wp-json\/wp\/v2\/comments?post=1101"}],"version-history":[{"count":1,"href":"https:\/\/scootercam.net\/blog\/wp-json\/wp\/v2\/posts\/1101\/revisions"}],"predecessor-version":[{"id":1102,"href":"https:\/\/scootercam.net\/blog\/wp-json\/wp\/v2\/posts\/1101\/revisions\/1102"}],"wp:attachment":[{"href":"https:\/\/scootercam.net\/blog\/wp-json\/wp\/v2\/media?parent=1101"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/scootercam.net\/blog\/wp-json\/wp\/v2\/categories?post=1101"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/scootercam.net\/blog\/wp-json\/wp\/v2\/tags?post=1101"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}