ZoneMinder on the Raspberry Pi 3


The Raspberry Pi 3 is the fastest Raspberry Pi, yet. It also adds onboard wifi and bluetooth. Here are some Pro's and Con's when using your Pi 3 as a ZoneMinder Server.

PROS: CONS:
  • Excellent software support from the manufacturer
  • 1GB DDR2 RAM is barely enough
  • Directly supported by several Linux distros, including Fedora
  • 10/100 Ethernet tied to the USB 2 bus
  • Dedicated Wifi/Bluetooth chip does not use the USB 2 bus
  • No provision for external storage w/o using the USB 2 bus




List of Materials

What follows is the list of materials I used to put together this project.

Install Fedora

I started this project before Fedora 25 was released. Consequently, the steps that follow were all performed on a Raspberry Pi 3 running Fedberry, a Fedora 24 spin. If you would like to follow along, simply go to that site and follow the instructions to download and write the Fedberry image file to your sd card. Just make sure and use the minimal image, which does not have a gui.

Alternatively, you can install Fedora 25 using these instructions from the Fedora team. The steps below will be the same.

Initial Prep

Assemble the hardware. It should be pretty straightforward. Note that I chose to partition and format the SSD as follows:
  1. 15GB ext4 partition for the Mariadb database files
  2. 454GB ext4 partition for the ZoneMinder events
  3. 512MB swap partition
  4. 512 MB empty space at end of drive
The idea behind the first partition is to get the database off the sd card. The second partition is straight forward. The third partition is swap because a small amount of swap space is a good thing. This will allow the Pi to swap out any processes not frequently used. I left 512MB of unused space at the end of the disk to allow the SSD to remap bad sectors should they ever occur.

With Fedberry installed and your Pi booted, you should see the SSD appear as /dev/sda. Let's put this aside for now.

Edit /boot/config.txt and set the parameter gpu_mem=16

vi /boot/config.txt
We now want to modify /etc/fstab. Fedberry uses a swap file, rather than a swap partition. We will change this. In addition, we will increase the size of the ramdisk, /dev/shm. Increasing the size of /dev/shm is a balancing act. You don't want to increase it too much. Otherwise you eat into the memory needed by the os, which can cause other problems. For now, use the value shown below. You can always change it again later once you get your cameras online:
We want to use ntpdate instead of ntp since ntpdate does not reside in memory:
sudo dnf remove ntp
sudo dnf install ntpdate

Issue sudo crontab -e and create the following crontab entry if it does not already exist:
0 0 * * * /usr/libexec/ntpdate-wrapper

Install the ZoneMinder RPM

In order to conserver memory, I put together an rpm which depends on nginx, rather than Apache. All you have to do is install it. The rpm will configure nginx for you.
To get it, hop on over to zmrepo.zoneminder.com and follow the installation instructions shown on the site. However, after zmrepo has been installed, instead of issuing yum install zoneminder do the following:
  1. Edit the file /etc/yum.repos.d/zmrepo-fedora-testing.repo and set the enabled flag under the [zmrepo-testing] block to 1.
  2. Now enter sudo dnf install zoneminder-nginx from the command line
  3. Finish up by following the steps in the README

Followup Configuration

Edit /etc/php-fpm.d/zoneminder.conf and remove the comments on the pm parameters:


1
2
3
4
# Uncomment these on machines with little memory
pm = ondemand
pm.max_children = 10
pm.process_idle_timeout = 10s

Stop mariadb and move the sql files onto the ssd:
sudo su
systemctl stop mariadb
cd /mnt
mkdir sda1
mount /dev/sda1 /mnt/sda1
chown mysql:mysql /mnt/sda1
mv /var/lib/mysql/* /mnt/sda1/
umount /mnt/sda1
exit
Now create the file /etc/systemd/system/var-lib-mysql.mount and add the following to it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# systemd mount unit for mysql storage
 
[Unit]
Description=systemd mount unit for mysql storage
Before=mariadb
 
[Mount]
What=/dev/disk/by-uuid/put_the_uuid_of_sda1_here
Where=/var/lib/mysql
Type=ext4
Options=defaults,noatime,commit=120,data=writeback
 
[Install]
WantedBy=multi-user.target

Enable and start the mount unit
sudo systemctl enable var-lib-mysql.mount
sudo systemctl start var-lib-mysql.mount
If successful, start mariadb back up:
sudo systemctl start mariadb
Let's do the same thing now for the ZoneMinder events folder
sudo su
systemctl stop zoneminder
cd /mnt
mkdir sda2
mount /dev/sda2 /mnt/sda2
chown nginx:nginx /mnt/sda2
mv /var/lib/zoneminder/events/* /mnt/sda1/
umount /mnt/sda2
exit
Create the file /etc/systemd/system/var-lib-zoneminder-events.mount and add the following to it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# systemd mount unit for ZoneMinder event storage
 
[Unit]
Description=systemd mount unit for ZoneMinder event storage
Before=zoneminder
 
[Mount]
What=/dev/disk/by-uuid/put_the_uuid_of_sda2_here
Where=/var/lib/zoneminder/events
Type=ext4
Options=defaults,noatime,commit=120,data=writeback
 
[Install]
WantedBy=multi-user.target

Enable and start the mount unit
sudo systemctl enable var-lib-zoneminder-events.mount
sudo systemctl start var-lib-zoneminder-events.mount
As a final step, we want to limit the amount of memory mariadb uses. There are several sample config files found in /usr/share/mysql which can help us do that. I chose the file my-medium.cnf:
sudo cp /usr/share/mysql/my-medium.cnf /etc/my.cnf.d/
Now edit my-medium.cnf and make the following changes:
  1. Un-comment skip-networking
  2. Un-comment all of the innodb_ parameters
Restart mariadb after saving your changes:
sudo systemctl restart mariadb
You can now start zoneminder. You did remember to follow the steps in the README, right? If you didn't, this is the point where things will start to go wrong for you.
sudo systemctl start zoneminder
At this point, you should be able to navigate to the ZoneMinder web console and start adding cameras. When adding a new monitor, decrease the image buffer for each new monitor from 50 to 35. This will save quite a bit of memory.

Performance

Here is a summary using sysbench:
  • cpu - 363.6433s
  • event storage drive - 18.307Mb/sec
  • database - 406.27 transactions per sec
We will compare these values to other single board computers as I review them.

Cameras

As you add cameras, ZoneMinder will consume space in your ramdisk, /dev/shm. You need to keep a close eye on this at all times. To make this easier, future versions of ZoneMinder will display the percent full in the top right of the web console. You should ensure there is at least ~200MB free of /dev/shm space. Other processes running on your system use the ramdisk. If you are just a little shy of the the target free space, consider increasing the size of /dev/shm a little bit further as described earlier.

You also need to keep an eye on your system load. A good not-to-exceed value for the raspberry pi is ~2.5 and ~3 while streaming a live view. Generally, you want to leave a free cpu core to perform non-ZoneMinder related tasks.

Not leaving enough "wiggle room" with cpu and ram resources is a leading cause of why ZoneMinder stops or crashses on its own over time.

I put the following table together to give you a rough estimate of how many resources are consumed as camera resolution is increased:

cameraformatresolutionfpsring buffer (frames)mmap (MB)Max swap buffer (MB)Zma (%)Zmc (%)Zms (%)
Airlink777WmjpegVGA535422410510
raspicamh264720p53512474302030
USGLBH245S400h2641080P535277176955055

As you can see, cpu and memory resources go up considerably as the resolution is increased. The cpu values are average over time. These values will spike when movement occurs within the field of view.

Note this data is only valid at 5 fps. CPU resources are expected go up linearly with an increase in frame rate e.g. double the frame, double the processing required.

From the table, you could theoretically attach ten VGA resolution cameras without any problem. Disk i/o might become the bottleneck in that case with so many cameras. However, jump up to 720p and a reasonable number is just three before you run out of space in your ramdisk.

Notice how the zms process for just a single 1080p camera consumed an entire cpu core! This is actually too much. Over a period of days, this camera would fall offline and reconnect, over and over, due to the excessive load. This is what drove me to look for a faster single board computer. Perhaps you will get better results, but at this time I would not recommend using a 1080p camera with a Raspberry Pi 3, unless you are willing to drop the frame rate even lower than 5.

Conclusion

While not designed for the role of a surveillance video recorder, the Raspberry Pi can be used successfully in a rather limited role. The USB 2 bus limits its i/o potential and its 1GB DDR2 ram is quickly consumed. However, if you are careful to stay within the resource limits, one can have some measured success.