Em's Site

How to store and backup Amcrest cameras using FTP on Linux

Date: Dec 12, 2021

Table Of Contents

Before we start, I should mention that my cameras are IP8M-2496EB. I think that the software is similar across the camera range, but YMMV.

I have a few Amcrest cameras at my house, and recently I decided to have a solid backup and storage system for the pictures and videos. It actually turned out to be pretty easy if you have a Linux machine with a lot of disk space (external hard drive/NAS would be best so that you don't fill up your main parition accidentally). I use a Raspberry Pi with an external hard drive.

Amcrest cameras have a built-in FTP client, so we'll set up an FTP server on our machine to initially receive the images and videos.

Setup

First, create an amcrest user for the camera's FTP client: sudo adduser amcrest. If you're doing this on a desktop or laptop, you can create a system user (adduser --system --group amcrest) so it doesn't show up on your login screen, but keep the home directory /home/amcrest and change the login shell in /etc/passwd to /bin/bash.

Next, install vsftpd (that's the package name on Ubuntu, other distros might be different). The default configuration will work; however if you want to access the media files without changing to the amcrest user, you can change local_umask to 022 (or even 002 if you want to delete them as well) and then add your normal user to the amcrest group.

Create a folder called ftp/ inside /home/amcrest. Log into your camera, and go to Setup (top right) > Storage > Destination > FTP. Check Enable, then fill in the rest of the details:

If you want to have the camera save to the SD card if it can't connect to the server, check the Emergency (Store on SD Card) box.

Finally, hit Save, and then Refresh, and then Test. The fun thing here is that even if it's set up correctly, the test will fail and say "List right loss" (??). If you see a folder in /home/amcrest/ftp, then it is working correctly. If you don't, make sure the details are correct and the permissions are correct for /home/amcrest/ftp. You can also check /var/log/vsftpd.log for any errors.

Backing up

Right now, the media is being saved in /home/amcrest/ftp. You could simply mount your external hard drive in that path and call it good, but Amcrest has a odd and cumbersome file structure and naming convention, so I created a Python script to rename and move the video and image files to my external drive. Here it is, commented for you:

import os
import re
import shutil

# Folder where the camera uploads the files
SRC_VIDEO_DIR = '/home/amcrest/ftp'

# Dictionary so we can make them better names, the key is the folder inside the ftp/ folder, the value is the folder we'll move it too
CAMERA_NAME_MAP = {
	'AMC046B3A2A06E5FCA': 'back-garage',
	'AMC0464D4DC6587927': 'front-garage',
}

# The folder where the videos will go to
TARGET_VIDEO_DIR = '/srv/disks/media2/camera'

for src_dir, target_dir in CAMERA_NAME_MAP.items():
	src_and_cam = f'{SRC_VIDEO_DIR}/{src_dir}'
	target_and_cam = f'{TARGET_VIDEO_DIR}/{target_dir}'
	if os.path.isdir(target_and_cam) is False:
		os.mkdir(target_and_cam)
	print(f'src: {src_and_cam}, target: {target_and_cam}')
	for date_folder in os.listdir(src_and_cam):
		if 'DVR' in date_folder:
			continue
		src_video_folder = f'{src_and_cam}/{date_folder}/video_001'
		src_image_folder = f'{src_and_cam}/{date_folder}/pic_001'
		target_path = f'{target_and_cam}/{date_folder}'
		if os.path.isdir(target_path) is False:
			os.mkdir(target_path)
		print(f'Entering {src_video_folder}')
		for old_video_name in os.listdir(src_video_folder):
			if 'mp4' not in old_video_name:
				continue
			new_video_name_regex = re.match(r'(?P<hr>\d{2})\.(?P<min>\d{2})\.(?P<sec>\d{2})', old_video_name)
			if new_video_name_regex is None:
				continue
			hr = new_video_name_regex.group('hr')
			minute = new_video_name_regex.group('min')
			sec = new_video_name_regex.group('sec')
			new_video_name = f'{hr}-{minute}-{sec}.mp4'
			full_old_video_path = f'{src_video_folder}/{old_video_name}'
			full_new_video_path = f'{target_path}/{new_video_name}'
			shutil.move(full_old_video_path, full_new_video_path)
			print(f'Moved {full_old_video_path} to {full_new_video_path}')
		for old_image_name in os.listdir(src_image_folder):
			if 'jpg' not in old_image_name:
				continue
			new_image_name_regex = re.match(r'(?P<hr>\d{2})\.(?P<min>\d{2})\.(?P<sec>\d{2})', old_image_name)
			if new_image_name_regex is None:
				continue
			hr = new_image_name_regex.group('hr')
			minute = new_image_name_regex.group('min')
			sec = new_image_name_regex.group('sec')
			new_image_name = f'{hr}-{minute}-{sec}.jpg'
			full_old_image_path = f'{src_image_folder}/{old_image_name}'
			full_new_image_path = f'{target_path}/{new_image_name}'
			shutil.move(full_old_image_path, full_new_image_path)
			print(f'Moved {full_old_image_path} to {full_new_image_path}')

This will iterate through the video and image files, get their timestamp, use that as the filename, then move them to the external hard drive grouped by date. Test it to make sure that the user has permissions to move the files, and then make a simple systemd service/timer to automate it.

Conclusion

Thanks for reading this! If you liked it, please share it with places that will also like it. If you are so inclined, you can buy me a Ko-Fi (other ways to donate are available as well). If you have any questions or comments, you can contact me in various ways, and I'll do my best to help you out. Follow me on Twitter to be notified of future posts and hear my thoughts.