DIY CCTV – Raspberry Pi IP Cameras and NVR

motionEye

I have an old CCTV DVR with two older analog cameras attached. It was all top of the line security gear 10 years ago when I was active in the field, and it has not aged well. The DVR has a very old and obviously no longer maintained android app, and the desktop software is just the same. I am not even sure if the company still sells standard DVRs anymore. The image quality on the cameras is horrible, somewhere around 480. To top it off my once prized analog security camera died while I was writing this.

Everything is IP and all the recorders are now NVRs these days. I was looking at possible new solutions to upgrading and there are some decent options out there. Theres the Blink XT2 and Arlo Pro cameras, they seem to be the most popular. There are also the super cheap (but indoor only at this time) Wyze cameras. They all have pretty decent apps but they all rely on cloud storage or record to local SD cards. If you want IP cameras without the cloud you are looking at going through a security professional or something you can get from Costco, Home Depot or Amazon etc. Now I can’t afford a new IP camera package at the moment but they seem nice, but with no local storage I decided to see if I could roll my own NVR and IP camera.

Before you go any further you should read this blog article, it has a ton of info on the options you have available to you. He goes in depth about the options, I am going to give you my experience with them, what I ended up sticking with and how I got it setup. I recommend trying out all the options if you are so inclined, it took me about a day or two to bounce between them all and settle on one. I have been writing this article for two weeks now.

I have a home server running on an old slim desktop computer (that someone dumped off on my curb one day). I am running Ubuntu Server 18.04 headless. I have a few programs and services running on it as well as a few terabytes of media that I cannot risk losing. Even losing the OS would be a pain in the ass as my Plex server would have to re-crawl the folders. That takes a long while, an event I would like to avoid if at all possible. So I am always hesitant on installing and trying new things that look like they need a lot of tweaking and trial & error. Enter the Raspberry Pi. This little SBC makes testing things perfect for me (I have still yet to dive into Docker and VMs). If it proves not too problematic then I can toss it on ye ole server.

I started writing this over a weekend, I thought I could turn my experience into a quick write up and oh man did this thing grow. I just want to state up front that I was kinda sideswiped during my process of doing this as a motionEyeOS prerelease came out and the official github has updated a few things which also match what I wrote here now (like they now cover the install on Buster which they did not before). So you may find some redundancies between our pages. Go figure.

My Requirements

  • Preferably runs off a Raspberry Pi, or at least a version Linux.
  • Low processor/memory requirements
  • Decent mobile support
  • Can live stream the UI via mobile or desktop
  • Motion detection of some sort
  • Ability to disable motion activation/recording via script or API (or GPIO buttons!)
  • The ability to send alerts (via email preferably)
  • Accepts more than one camera (ideally up to 4 or 5)
  • Nice multi-camera view
  • The ability to take a snapshot and/or record video on an external trigger (like GPIO buttons!)

 

The Options

  1. ZoneMinder
  2. Kerberos.io
  3. Shinobi
  4. Motion
  5. MotionEye/MotionEyeOS

 

The Cameras

I have decided to use a Raspberry Pi Zero W and a Raspberry Pi v2.1 camera module as my homebrew IP camera. The second camera I am using is a Wyze Cam 2. A small and super awesome $20 1080 IP camera. Wyze just released a beta version of firmware to give RTSP features to their cheap $20 v2 cameras. Of course some things may be too good to be true? There are reports floating around the web (mostly Reddit, of course) on the policies of the (Chinese) parent company. It just so happens that there is also 3rd party firmware out there to remove all default features of the camera and make it a pure RTSP IP camera (this kills all phoning-home and app abilities). So if that shit bothers you can can turn the Wyze Cam 2 into a pure RTSP camera (no app features).

Updating the firmware on a Wyze 2.0 camera for RTSP support (maintains app features)

Original Wyze firmware if you want to go back to stock

Xiaomi Dafang Hacks, turn the camera app features off and pure RTSP (I have not tested this)

 

Raspberry Pi as a IP Camera

If you are using an RPi as an IP camera you have a few options available to you on exactly what software you want to use to get it done with. The options for streaming IP camera footage are:

 

motionEyeOs as an IP camera

To use motionEyeOS as an IP camera with a Raspberry Pi just connect a RPi camera to the unit and flash the SD with the motionEyeOS software. Once the Pi boots it should have automatically configured itself for the camera (you should see video on the web GUI). Now you could get away with motionEyeOS installed on a Pi with a camera as an all in one IP NVR solution. It may work well for this, I have not tested it this way. I intended to use it to stream the camera footage. A few things I’ve noticed:

  • The RPi Zero W takes a long time to boot up, 2-5 minutes to boot and gain WiFi
  • The RPi Zero W sometimes locks up and requires a hard reset, often.
  • The RPi Zero W sometimes slows down if it doesn’t lock up, requiring a reboot.
  • Fast network camera toggle disables most features, it is meant for using the Pi as a camera to stream to another server.

When you have Fast Network Camera enabled, you’ll notice that:

  • Your motionEyeOS-based camera can reach a significantly higher frame rate, at a higher resolution.
  • You can tweak many CSI camera-specific parameters directly from the UI
  • Your browser will eat up less CPU at the same frame rate/resolution (it uses a pure MJPEG stream, rather than triggering every refresh from JavaScript)

On the other hand, this doesn’t come without some disadvantages:

  • No more motion detection (on the Pi itself, another motionEye server can still handle motion detection)
  • No more motion notifications (on the Pi itself, another motionEye server can still handle motion detection)
  • No more pictures or movies (on the Pi itself, another motionEye server can still handle motion detection)
  • No more overlaid text (date/time, camera name) (on the Pi itself, another motionEye server can still handle motion detection)
  • A significantly higher network bandwidth usage

Most of my time spent testing motionEyeOS on a RPi Zero W was spent rebooting the unit and trying to figure out why it was locking up and freezing constantly. I was not able to get more than a few hours out of it without it needing to be rebooted. I moved on. There are a few options to go through below, they all do the basic same thing. Some just work better than others or use different codecs etc.

 

VLC (with raspivid)

Video LAN player has been around for a long time, and it has a lot of different uses. In this case we are just interested in streaming a video feed over the network (I have found this to be the best way to stream the IP footage from a PI Zero W).

 

VLC with the v4l2 driver.

There are a ton of different flags you can call for many different options. For example I found this on the internet, looks like it transcode the stream – not good for a Pi.

cvlc -vvv v4l2:///dev/video0 --sout '#transcode{vcodec=mp2v,vb=800,acodec=none}:rtp{sdp=rtsp://:8554/}'

Some basic flags.

cvlc is the console vlc player
-vvv and its argument specifies where to get the stream from
-sout and its argument specifies where to output it to

We can specify HTTP or RTSP protocol for the stream.

https://wiki.videolan.org/Documentation:Streaming_HowTo/Command_Line_Examples/

https://raspberry-projects.com/pi/pi-hardware/raspberry-pi-camera/streaming-video-using-vlc-player

https://raspberrypi.stackexchange.com/questions/23182/how-to-stream-video-from-raspberry-pi-camera-and-watch-it-live

 

UV4L

https://www.instructables.com/id/Raspberry-Pi-Video-Streaming/

Installation for ARM devices

Stretch only at this time (08-25-2019)

curl http://www.linux-projects.org/listing/uv4l_repo/lpkey.asc | sudo apt-key add -

and add the following line to the file /etc/apt/sources.list:

sudo nano /etc/apt/sources.list deb http://www.linux-projects.org/listing/uv4l_repo/raspbian/stretch stretch main

Finally, we are ready to update the system and to fetch and install the packages:

 

If you want the driver to be loaded at boot, also install this optional package:

sudo apt-get install uv4l-raspicam-extras

As a convenience, the above package will install a service script for starting, stopping or restarting the driver at any time, for example:

sudo service uv4l_raspicam restart

 

Test the module

uv4l --driver raspicam --auto-video_nr --width 640 --height 480 --encoding jpeg

To manually terminate a running driver, close all the applications accessing the device and kill the corresponding uv4l process:

pkill uv4l

 

Omxplayer

We can use omxplayer or VLC (cvlc)

omxplayer github site

For the screen we use omxplayer rtsp://12.34.56.78/live

If we want to simply output to an HDMI source then we can add the -o flag.

-o hdmi outputs the audio to the hdmi port

 

V4L2rtspserver

v4l2streamer github page and information

You need to have make and cmake installed.

To use it:

v4l2rtspserver -F15 -H 972 -W1296 -P 8555 /dev/video0  

I went with VLC player with raspivid and it has been working flawlessly for a few weeks. So lets make it a service and auto run it on boot so it just boots and streams happily away.

 

Create a service

  1. Create a file sudo nano /usr/bin/streamrtsp.sh
  2. Make it executable:
  3. Create a Unit file to define a systemd service: sudo nano /lib/systemd/system/streamrtsp.service
  4. This defines a simple service. The critical part is the ExecStart  directive, which specifies the command that will be run to start the service.
  5. Copy the unit file to /etc/systemd/system   and give it permissions
  6. Reload systemctl  sudo systemctl reload
  7. Enable and start the new service

Realistic expectations

Now before we get all crazy let’s be real for a minute. A Raspberry Pi is not going to replace a standalone commercial NVR, no. I am not looking for stellar performance and I expect to have to manage this project for a while (updating and tweaking etc). I am also not using 4k or anything crazy for my streams. I am simply looking for a low cost upgrade solution to my current ailing CCTV system.

 

ZoneMinder

After reading Jason Antman’s blog I decided to try ZoneMinder first. It seemed to fit the bill, mostly. But when I went to look at the install requirements I changed my mind. There is no simple (or simpler) install process for ZoneMinder on the Raspberry Pi, or even Debian for that matter as both install processes are pretty much the same. The ZoneMinder website has a guide to walk you through the install process but it is a long one. I did not want to waste my time on an older program I would probably not like (I am a sucker for a nice web GUI). So away with you ZoneMinder!

 

Kerberos.io

Next up was Kerberos.io. It looks to be the shiniest of the Linux NVR solutions I found so far. But upon re-reading Jason Antman’s blog again before I ran through the install I found Kerberos.io only supports ONE camera. To get more than one camera you need to spawn more than one instance of Kerberos. Fuck that! I mean if you are planning on only having one camera perhaps this is the way to go, but I am not and I want room to grow. But it does look nice. Didn’t even get out of the gate.

 

Shinobi

After getting nowhere with ZoneMinder and Kerberos.io I set my sights on Shinobi. Shinobi looked to have a great interface and the documentation wasn’t hard to find. Shinobi supports Ubuntu, CentOS, and MacOS which is different than most NVR softwares.

Installing Shinobi is pretty straight forward and easy

sudo bash <(curl -s https://gitlab.com/Shinobi-Systems/Shinobi-Installer/raw/master/shinobi-install.sh)

Once finished you can open up http://yourraspberrypiIP:8080 or http://raspberrypi.local  in your browser.

http://yourraspberrypiIP:8080/super or http://raspberrypi.local/super  is the address for the admin side. This allows you to edit and add users.

I could not for the life of me get either of my two IP cameras to work. Shinobi had no problem loading but the cameras would not load no matter what settings I tried. I spent a few hours on it but nothing crazy. I also did not really dive into the issue as I was testing software to see what fit, and having major issues right from the start was a flag for me.

Shinobi official docs

Shinobi SubReddit

 

motion

https://motion-project.github.io/

motion is a nice lightweight Linux supported piece of software for streaming and viewing streams of IP cameras. It has tons of features, create and save videos or pictures on motion enabled events, schedule recordings, on the fly capture, view live streams and much more. Only drawback is it has no interface. It is command line driven. All of the configuration and setup are done with config files. Ugh. Not what I was looking for at all, thanks Linux.

 

motionEye/motionEyeOS

First off they’re the same thing. One pertains to a manual installation and the other the prebuilt image. As far as I know is the support and features are the same, same product as far as I am aware. motionEyeOS has a few more features than motionEye installed on top of something else like Raspbian. But you lose the ability to do anything else with the Pi as the image is rather small (around 50mb) and has a very limited set of packages installed.

There is also an Android version of motionEyeOS, you don’t even need a computer or a Raspberry Pi to run it. An old cellphone will work (and probably better), most phones are faster and have much more ram than a RPi. The caveat with the Android version is that it only supports motionEye cameras no RTSP IP cameras. Major drawback.

 

 

My Pick

motionEye/motionEyeOS

I decided to run with motionEye over motionEyeOS, I like the ability of having a full distro behind the Pi. More options are available. But there is nothing wrong with motionEyeOS, it is a great piece of software.

First off, motionEye runs the Pi HOT. You are going to need a cooling solution of some sort. I ran the Pi with motionEye for a few days with no fan and to IP cameras running at 15-20fps and the Pi was sitting at a constant 72C, pretty hot (ambient temp is about 24C). It slows itself down at 80C. With the Noctua fan and the same exact setup the Pi is sitting at a nice 41.3C at idle, and only jumps up to 52.1C when viewing motionEye feeds for long periods of time. Most of the research these days for the Pi show that it is best to use just a straight fan over the CPU. No heatsink needed, and a heatsink alone wont help much with the heat motionEye puts off. They make fan shims and cases for the Pi. I highly recommend a Noctua 40mm fan (NF-A4x10 5v), they are a little pricey as fans go but they are super silent. I have my motionEye Pi running on my computer desk and I don’t notice it. Whatever fan you use make sure it is 5v!

You can keep an eye on your Pi temps with this command

vcgencmd measure_temp

 

Installing motionEye via prebuilt image

You can view the official installation instructions here motionEyeOS install from the wiki – RaspbianUbuntu

Go here and download the most current stable version (or a dev version if you’re brave)

Make sure you download the proper image for the right device/OS. We are using a Raspberry Pi 3B+ for this guide.

Once downloaded you need to flash the image to the SD card for the Pi. Balena Etcher is my preferred choice. You can use whatever method you like. After the image is flashed to the card go ahead and add the usual Raspberry Pi wpa_supplicant.conf  file and SSH  file so motionEyeOS will connect to our WiFi and allow us SSH access.

Once booted you are now in motionEyeOS! Proceed to change the settings and add cameras.

Installing motionEye on Raspbian Stretch Lite

Follow these steps for Raspbian Stretch Lite if you do not want to use the prebuilt image.

 

Installing motionEye on Raspbian Buster Lite

It is pretty close to the same install as stretch (and the instructions on the motionEye website). I have noticed one difference, installing motionEye on top of Raspbian did not give me the option to use a network share as camera storage the first time, but it did the second time around. So keep that in mind before going forward.

 

First, as always – update, then upgrade

Don’t forget to run through raspi-config  at least once. Set the local time, language locale, hostname and set the memory split. Give a hefty chunk to the GPU..

 

Install ffmpeg (this part takes the longest)

 

Install libmicrohttpd12 , libmariadb3  and libpq5  required by motion 4.2.2

 

Install motion  v4.2.2 (current as of this posting 09/2019)

 

Install files required by motionEye

 

Install some pip dependancies for motionEye

sudo pip install pytz

 

Install motionEye

That should also install the dependancies tornado , jinja2 , pillow  and pycurl

 

Prepare the motionEye configuration directory

 

Prepare the motionEye media directory

 

Add an init script and configure it to run the motionEye server on startup

If you are ok with the motionEye defaults or just want to dive right in go ahead and load it up, otherwise go a little bit further and configure motionEye first

sudo systemctl start motioneye

 

Configure motionEye

And now you have motion and motionEye installed. Time to configure motionEye. We can edit the motioneye.conf  file and make any changes to the defaults. Such as the GUI interface port (default is 8765 ), timeouts, restart on error, enable the GUI to edit wifi settings same with the time, enable reboot and shutdown, hostname. https://github.com/ccrisan/motioneye/wiki/Configuration-File

 

You can change the default path here if you already know where you want the files stored

 

I changed the default port to 80  as I am not using this Pi for anything other than motionEye

 

I set this to true, I want this thing to run 24/7 without intervention as much as possible

 

Change the mount point of network shares if you want

 

I want to be able to edit the WiFi credentials from the GUI so we need to enable this (this is the path for Buster)

 

I also want to be able to edit the timezone from the GUI

 

We want to be able to reboot and shutdown the system from the GUI as well

 

And then we can change the hostname if we want. It defaults to raspberrypi  which you can change from using raspi-config  or we can override it here. I would still use raspi-config  as I could not get this to take on my install

 

Now we can start (or reload) motionEye

 

In the future, to upgrade to the newest version of motionEye, just issue:

 

 

Installing motionEye with Docker

Docker Image

https://github.com/ccrisan/motioneye/wiki/Install-In-Docker

I have not dived into the world of containers yet so I have not tested this out, but it is available.

 

Adding External storage

There are a few options you have to work with. You could just use a large SD card and store all the video and picture accumulated on there with the OS. But the issues with limited read/writes with SDs make this less than ideal. If you have a NAS or a server with some network shares you can offload the storage there. Or you can use a USB flash drive or hard drive. I have an old 80gb USB hard drive I have laying around so thats what I am using.

With motionEye I had to mount the drive myself. With motionEyeOS the disk was autodetected and mounted at boot. If your device does not auto mount you will need to do it manually. The following information is taken from the Raspberry Pi website.

See here https://www.raspberrypi.org/documentation/configuration/external-storage.md

 

Run the following command to get the location of the disk partition:

 

For example (and usually) the drive is /dev/sda1

Create a target folder to be the mount point of the storage device. The mount point name used in this case is storage . You can specify a name of your choice:

 

Mount the storage device at the mount point you created:

 

Verify that the storage device is mounted successfully by listing the contents:

 

Automatic mounting at boot

You can modify the fstab  file to define the location where the storage device will be automatically mounted when the Raspberry Pi starts up. In the fstab  file, the disk partition is identified by the universally unique identifier (UUID) or you can specify the location like /dev/sda1 .

Get the UUID of the disk partition:

Find the disk partition from the list and note the UUID. For example, 5C24-1453 .

 

Open the fstab  file using a command line editor such as nano

 

Add the following line in the fstab  file:

Replace FSTYPE  with the type of your file system, which you found above using the blkid  command.

 

If you need to remove the device, unmount it first.

 

 

Add an RTC to motionEye

I was unable to edit the appropriate files and add an RTC with motionEyeOS, they didn’t exist.

Using a DS1307 RTC

Log in remotely via SSH/putty and create/edit the file /data/etc/modules

Add the following line, save and exit the editor

Create/edit the file /data/etc/userinit.sh

Add the following lines, save and exit the editor

Reboot

Now test with sudo hwclock -r

If done correctly it should spit out the date and time, if the date and time is off you can try adjusting it via the web GUI. Set the local timezone again and reboot, then test again. you should be good to go.

 

Using a DS3231 RTC

There are only two edits that need to be done to get the DS3231 working, put the below line into the /boot/config.txt dtoverlay=i2c-rtc,ds3231

Edit /lib/udev/hwclock-set  file and “comment out” the following lines a few lines

sudo nano /lib/udev/hwclock-set That’s it, that’s all you need to do. Shutdown your system and remove power,  connect the RTC module, then power up and test with the command:

sudo hwclock -r

If done correctly it should spit out the date and time, if the date and time is off you can try adjusting it via the web GUI. Set the local timezone again and reboot, then test again. you should be good to go.

 

A few extra RTC commands

Read time directly from RTC module

hwclock -r

Update RTC module time from system time (system time should be regularly updated by NTP from the internet if your Pi is networked)

hwclock -w

Update system time from the RTC module (this should happen on startup)

hwclock -s

 

 

Using an Raspberry Pi Zero and 3.5″ LCD to view streams

In short, not so hot an idea. I wanted to entertain the idea of using the dust collecting waveshare 3.5″ LCD screen I have for the Pi. I have had it for a few years and never found a decent use for it. So i figured I could use it and a Zero as a dedicated screen to view a camera stream.

There are basically two choices that I found. Omxplayer and VLC.

 

Create a Pi with a 3.5″ waveshare LCD screen

This should install with the screen to boot with the bottom being the power plug, if you want it the other way do this instead

Reboot your Raspberry Pi and make sure you get video on your LCD.

Once the Pi reboots login over SSH or with a keyboard/mouse and now all you need to do is launch the viewer to see the feed on the screen.

It worked, but horribly. The framerate on the waveshare is so low the LCD is unusable for pretty much any IP camera viewing, this was on a RPi Zero W with the 3.5″ screen.

 

For future to-do

I have come across a few ways to trigger an event with motionEye. So it is possible to have an external trigger activate motion detection, or other alarms (GPIOs even). I’ll write more on that later when I get to those needs.

https://www.raspberrypi.org/forums/viewtopic.php?t=220385

 

Monochrome/black & white

You may also notice that monochrome images from cameras give a far superior picture. The Wyze cam I have will do monochrome in low light and I get more detail with that picture than I do with the color image. On that camera I can force it, I have not found a good way to do this with a Raspi-camera.

raspivid -o - -t 0 -w 1280 -h 720 -fps 20 -b 250000 -cfx 128:128 | cvlc -vvv stream:///dev/stdin --sout '#rtp{access=udp,sdp=rtsp://:8554/unicast}' :demux=h264

But it does not give you real cctv monochrome. You don’t gain anything by switching to BW on a Pi like yo u do on real security cameras. Usually the resolution of the image increases – you gain more details with the absence of color.

Ii could not find anything related to true black and white camera for the Pi, or a way to remove the color filter. I don’t think it’s possible.

 

 

Some links I found helpful

CCTV RPi system with storage (RPI with a USB HDD and RPI Zeros as IP cams)

Pi3 RTSP Stream Viewer for 4 cameras?

Linus Tech Tips on motionEyeOS (Youtube video)

how to display cctv camersas in the dashboard

Simple RTSP server for a Pi

Simple Pi camera streamer

How to stream on a raspberry pi – stack exchange

youtube video on Node-Red as an NVR with IP cameras

Here is the Node-Red flow to go along with the Youtube video

script to display RTSP IP camera feeds on the Raspberries HDMI

Interesting script for displaying multiple RTSP feeds on a monitor/TV via HDMI

 

 

 

Leave a Reply

%d bloggers like this: