Setting up the software

This time, we have to set up two programs: the mailer and the motion detection system. The former, used to send the alarm e-mail message, is very simple and easy to set up; while the latter, used to implement the intrusions detection system, is a bit more complicated due to the fact that it supports tons of different devices and features.

Setting up the mailer

As requested by this project, we should alert the user about possible intrusions by sending them an e-mail. There exists several ways to send an e-mail on a UNIX-like system, and the most commonly used is the mail command that is called with the following command:

echo "Test message" | mail -s "test mail" [email protected]

Note

For further information about the mail program, the reader can take a look at its man pages (using the man mail command) or start reading about it at https://en.wikipedia.org/wiki/Mail_%28Unix%29.

The real problem is that this command relays on the system mailer, which is the real program that actually sends our letters over the Internet! By default, our BeagleBone Black has no valid mailer, so, if we try to send an e-mail message with the mail program, we get the following error:

root@beaglebone:~# echo "Test message" | mail -s "test mail"[email protected]
root@beaglebone:~# /usr/lib/sendmail: No such file or directory
"/root/dead.letter" 8/200
. . . message not sent.

Tip

The -s option argument used in the preceding output is to specify a subject for the e-mail.

To solve our problem, we have to install a valid /usr/lib/sendmail program, and, as already stated, there are several ways to do it. I decided to use the ssmtp tool with my Gmail account.

Note

Note that the ssmtp tool is a generic tool to be used with a mailhost, so it is not a Gmail-related product. For further information on the tool, you can take a look at https://wiki.debian.org/sSMTP.

To install it, we can use the usual aptitude command with two other useful tools for e-mail processing:

root@beaglebone:~# aptitude install ssmtp mailutils mpack

After the installation, we have to modify the /etc/ssmtp/ssmtp.conf configuration file according to the following patch:

--- /etc/ssmtp/ssmtp.conf.orig   2015-09-11 21:52:39.531475392 +0000
+++ /etc/ssmtp/ssmtp.conf   2015-09-11 21:56:01.859600416 +0000
@@ -18,4 +18,10 @@
 # Are users allowed to set their own From: address?
 # YES - Allow the user to specify their own From: address
 # NO - Use the system generated From: address
-#FromLineOverride=YES
+FromLineOverride=YES
+
+# Add GMail settings
+mailhub=smtp.gmail.com:587
[email protected]
+AuthPass=XXXXXXXXXX
+useSTARTTLS=YES

The FromLineOverride setting has been enabled since we wish to specify our own From: address; then, the other fields are needed so we can send an e-mail message via our Gmail account.

Tip

For obvious reasons, I replaced my password with the XXXXXXXXXX string. Of course, you have to set up the AuthUser and AuthPass settings to suite your Gmail account.

If everything works well, we should now be able to send an e-mail using the following command:

root@beaglebone:~# echo "Test message" | mail -s "Test subject" -r "BBB Guardian <[email protected]>" [email protected]

Tip

Note that if your Gmail credentials are not correctly set up, you may get the following error message:

send-mail: Authorization failed (535 5.7.8  https://support.google.com/mail/answer/14257 fr10sm1091535wib.14 – gsmtp)

Also, note also that the -r option argument is used to specify a sender name; so, in the preceding example, in the From: field is displayed the BBB Guardian <[email protected]> string, otherwise, the Gmail address is displayed instead.

The following screenshot shows the message as received on my smartphone:

Setting up the mailer

Using motion

 

Motion is a program that monitors the video signal from cameras. It is able to detect if a significant part of the picture has changed; in other words, it can detect motion.

 
 --[Motion WebHome]

Note

Visit the project homepage is at http://www.lavrsen.dk/foswiki/bin/view/Motion/WebHome.

The software is a libre CCTV software application developed for GNU/Linux-based systems, and as stated on the program's home site, it can monitor the video signal from one or more cameras and is able to detect if a significant part of the picture has changed, saving video when it detects that motion is occurring.

The program is a command-line-driven tool written in C and made for the Video4Linux interface. It can run as a daemon with a rather small footprint and low CPU usage. It can call to user configurable triggers when certain events occur, and then it generates either pictures (.jpeg, .netpbm) or videos (.mpeg, .avi).

motion is operated mainly via configuration files though the end video streams that can be viewed from a web browser.

Downloading the code

Downloading and installing motion on the BeagleBone Black is quite simple, since we simply have to use the usual command to install a new package as follows:

root@beaglebone:~# aptitude install motion
...
Setting up motion (3.2.12-3.4) ...
Adding group `motion' (GID 117) ...
Done.
Adding system user `motion' (UID 111) ...
Adding new user `motion' (UID 111) with group `motion' ...
Not creating home directory `/home/motion'.
Adding user `motion' to group `video' ...
Adding user motion to group video
Done.
[ ok ] Starting motion (via systemctl): motion.service.

When all the code is installed, it's time to configure the program! In fact, if we take a look at the system's log messages, we see the following output:

root@beaglebone:~# tail -f /var/log/syslog
...
Sep  4 15:18:41 beaglebone motion[4511]: Not starting motion daemon, disabled via /etc/default/motion ... (warning).

The daemon is disabled by default due to the fact that it must be correctly configured before enabling it. So, let's see how we can do this in the next section.

Configuring the daemon

To configure the daemon in order to use two webcams, we have to modify three files: the main configuration file /etc/motion/motion.conf, the configuration files of each webcam /etc/motion/thread1.conf, and /etc/motion/thread2.conf. The daemon creates one thread per webcams used, and all special settings referring to a webcam must be set inside the corresponding file.

Let's start by modifying the /etc/motion/motion.conf file. First of all, we must enable one thread per webcam, so we have to apply the following patch:

--- motion.conf.orig   2014-04-23 21:12:18.511719124 +0000
+++ motion.conf   2014-04-23 21:12:47.710937877 +0000
@@ -630,8 +630,8 @@
 # This motion.conf file AND thread1.conf and thread2.conf.
 # Only put the options that are unique to each camera in the
 # thread config files.
-; thread /usr/local/etc/thread1.conf
-; thread /usr/local/etc/thread2.conf
+thread /etc/motion/thread1.conf
+thread /etc/motion/thread2.conf
 ; thread /usr/local/etc/thread3.conf
 ; thread /usr/local/etc/thread4.conf

Then, we can verify the setting by running the motion daemon in debugging mode with the following command:

root@beaglebone:~# motion -s -n
[0] Processing thread 0 - config file /etc/motion/motion.conf
[0] Processing config file /etc/motion/thread1.conf
[0] Processing config file /etc/motion/thread2.conf
[0] Motion 3.2.12 Started
[0] ffmpeg LIBAVCODEC_BUILD 3482368 LIBAVFORMAT_BUILD 3478785
[0] Motion running in setup mode.
[0] Thread 1 is from /etc/motion/thread1.conf
[0] Thread 1 is device: /dev/video0 input 8
[0] Webcam port 8081
[0] Thread 2 is from /etc/motion/thread2.conf
[0] Thread 2 is device: /dev/video1 input 1
[0] Webcam port 8082
[0] Waiting for threads to finish, pid: 3096
[1] Thread 1 started
[0] motion-httpd/3.2.12 running, accepting connections
[0] motion-httpd: waiting for data on port TCP 8080
[2] Thread 2 started
[1] cap.driver: "uvcvideo"
[1] cap.card: "Microsoft LifeCam VX-800"
[1] cap.bus_info: "usb-musb-hdrc.1.auto-1.1"
[1] cap.capabilities=0x84000001
[1] - VIDEO_CAPTURE
[1] - STREAMING
[1] Config palette index 8 (YU12) doesn't work.
[1] Supported palettes:
[1] 0: YUYV (YUV 4:2:2 (YUYV))
[1] Selected palette YUYV
[1] Test palette YUYV (320x240)
[1] Using palette YUYV (320x240) bytesperlines 640 sizeimage 153600 colorspace 00000000
[1] found control 0x00980900, "Brightness", range -10,10
[1]    "Brightness", default 2, current 2
[1] found control 0x00980901, "Contrast", range 0,20
[1]    "Contrast", default 10, current 10
[1] found control 0x00980902, "Saturation", range 0,10
[1]    "Saturation", default 4, current 4
[1] found control 0x00980903, "Hue", range -5,5
[1] 	"Hue", default 0, current 0
[1] found control 0x00980910, "Gamma", range 100,200
[1]    "Gamma", default 130, current 130
[1] found control 0x00980913, "Gain", range 32,48
[1]    "Gain", default 34, current 34
[1] mmap information:
[1] frames=4
[1] 0 length=153600
[1] 1 length=153600
[1] 2 length=153600
[1] 3 length=153600
[1] Using V4L2
[2] cap.driver: "gspca_zc3xx"
[2] cap.card: "USB Camera (046d:08a2)"
[2] cap.bus_info: "usb-musb-hdrc.1.auto-1.2"
[2] cap.capabilities=0x85000001
[2] - VIDEO_CAPTURE
[2] - READWRITE
[2] - STREAMING
[2] Unable to query input 1 VIDIOC_ENUMINPUT: Invalid argument
[2] ioctl (VIDIOCGCAP): Inappropriate ioctl for device
[2] Could not fetch initial image from camera
[2] Motion continues using width and height from config file(s)
[1] Resizing pre_capture buffer to 1 items
[2] Resizing pre_capture buffer to 1 items
[2] Started stream webcam server in port 8082

As we can see from the preceding output, we can get a lot of useful information about the daemon status. First of all, we notice that each line begins with a number in square brackets that address per thread output. The number 0 is for the motion main thread, the number 1 is for the first thread connected to the first webcam (device /dev/video0), and the number 2 is for the second thread connected to the second webcam (device /dev/video1).

Then, we see that for the first webcam, the daemon says gives us the following output:

[1] cap.driver: "uvcvideo"
[1] cap.card: "Microsoft LifeCam VX-800"
[1] cap.bus_info: "usb-musb-hdrc.1.auto-1.1"
[1] cap.capabilities=0x84000001
[1] - VIDEO_CAPTURE
[1] - STREAMING
[1] Config palette index 8 (YU12) doesn't work.
[1] Supported palettes:
[1] 0: YUYV (YUV 4:2:2 (YUYV))
[1] Selected palette YUYV

That is the current palette setting (YU12) is not valid for the webcam and the system says that it is going to use YUYV.

And an error message is displayed for thread 2:

[2] cap.driver: "gspca_zc3xx"
[2] cap.card: "USB Camera (046d:08a2)"
[2] cap.bus_info: "usb-musb-hdrc.1.auto-1.2"
[2] cap.capabilities=0x85000001
[2] - VIDEO_CAPTURE
[2] - READWRITE
[2] - STREAMING
[2] Unable to query input 1 VIDIOC_ENUMINPUT: Invalid argument
[2] ioctl (VIDIOCGCAP): Inappropriate ioctl for device
[2] Could not fetch initial image from camera

This time, it seems like a severe error, but let's go step by step and fix the first camera. In the /etc/motion/thread1.conf file, we see the following settings (the following is just a snippet of the whole file):

# Videodevice to be used for capturing  (default /dev/video0)
# for FreeBSD default is /dev/bktr0
videodevice /dev/video0

# The video input to be used (default: 8)
# Should normally be set to 1 for video/TV cards, and 8 for USB cameras
input 8

The videodevice and input settings are correct, but the video palette setting is missing, so the default one is used. As seen in the preceding output, it's wrong. To fix it, we must add the following lines:

--- /etc/motion/thread1.conf.orig   2014-04-23 21:12:25.712890999 +0000
+++ /etc/motion/thread1.conf   2014-04-23 20:25:15.089843787 +0000
@@ -12,6 +12,25 @@
 # for FreeBSD default is /dev/bktr0
 videodevice /dev/video0
 
+# v4l2_palette allows to choose preferable palette to be use by motion
+# to capture from those supported by your videodevice. (default: 8)
+# E.g. if your videodevice supports both V4L2_PIX_FMT_SBGGR8 and
+# V4L2_PIX_FMT_MJPEG then motion will by default use V4L2_PIX_FMT_MJPEG.
+# Setting v4l2_palette to 1 forces motion to use V4L2_PIX_FMT_SBGGR8
+# instead.
+#
+# Values :
+# V4L2_PIX_FMT_SN9C10X : 0  'S910'
+# V4L2_PIX_FMT_SBGGR8  : 1  'BA81'
+# V4L2_PIX_FMT_MJPEG   : 2  'MJPEG'
+# V4L2_PIX_FMT_JPEG    : 3  'JPEG'
+# V4L2_PIX_FMT_RGB24   : 4  'RGB3'
+# V4L2_PIX_FMT_UYVY    : 5  'UYVY'
+# V4L2_PIX_FMT_YUYV    : 6  'YUYV'
+# V4L2_PIX_FMT_YUV422P : 7  '422P'
+# V4L2_PIX_FMT_YUV420  : 8  'YU12'
+v4l2_palette 8
+
 # The video input to be used (default: 8)
 # Should normally be set to 1 for video/TV cards, and 8 for USB cameras
 input 8

Note that I set the entry v4l2_palette to 6 in order to select the YUYV palette. Now, if we rerun the daemon, we get the following output:

[2] Thread 2 started
[1] cap.driver: "uvcvideo"
[1] cap.card: "Microsoft LifeCam VX-800"
[1] cap.bus_info: "usb-musb-hdrc.1.auto-1.1"
[1] cap.capabilities=0x84000001
[1] - VIDEO_CAPTURE
[1] - STREAMING
[1] Test palette YUYV (320x240)
[1] Using palette YUYV (320x240) bytesperlines 640 sizeimage 153600 colorspace 00000000

Great! Now, let's fix the configuration file for the second webcam. In the /etc/motion/thread2.conf file, we see the following output:

# Videodevice to be used for capturing  (default /dev/video0)
# for FreeBSD default is /dev/bktr0
videodevice /dev/video1

# The video input to be used (default: 8)
# Should normally be set to 1 for video/TV cards, and 8 for USB cameras
input 1

Again, the videodevice setting is correct, but the input setting is not! So, let's fix it as shown in the following patch and then rerun the daemon:

--- /etc/motion/thread2.conf.orig   2014-04-23 21:12:30.703125375 +0000
+++ /etc/motion/thread2.conf   2014-04-23 20:31:54.214843835 +0000
@@ -14,7 +14,7 @@
 
 # The video input to be used (default: 8)
 # Should normally be set to 1 for video/TV cards, and 8 for USB cameras
-input 1
+input 6
 
 # Draw a user defined text on the images using same options as C #function strftime(3)
 # Default: Not defined = no text

Now, the daemon output for the second thread is changed as follows:

[2] cap.driver: "gspca_zc3xx"
[2] cap.card: "USB Camera (046d:08a2)"
[2] cap.bus_info: "usb-musb-hdrc.1.auto-1.2"
[2] cap.capabilities=0x85000001
[2] - VIDEO_CAPTURE
[2] - READWRITE
[2] - STREAMING
[2] Config palette index 8 (YU12) doesn't work.
[2] Supported palettes:
[1] Resizing pre_capture buffer to 1 items
[2] 0: JPEG (JPEG)
[2] Selected palette JPEG

So, we have to modify the /etc/motion/thread2.conf file again as shown in the following patch:

--- /etc/motion/thread2.conf.orig   2014-04-23 20:34:51.173828231 +0000
+++ /etc/motion/thread2.conf   2014-04-23 20:34:32.744140729 +0000
@@ -12,6 +12,25 @@
 # for FreeBSD default is /dev/bktr0
 videodevice /dev/video1
 
+# v4l2_palette allows to choose preferable palette to be use by motion
+# to capture from those supported by your videodevice. (default: 8)
+# E.g. if your videodevice supports both V4L2_PIX_FMT_SBGGR8 and
+# V4L2_PIX_FMT_MJPEG then motion will by default use V4L2_PIX_FMT_MJPEG.
+# Setting v4l2_palette to 1 forces motion to use V4L2_PIX_FMT_SBGGR8
+# instead.
+#
+# Values :
+# V4L2_PIX_FMT_SN9C10X : 0  'S910'
+# V4L2_PIX_FMT_SBGGR8  : 1  'BA81'
+# V4L2_PIX_FMT_MJPEG   : 2  'MJPEG'
+# V4L2_PIX_FMT_JPEG    : 3  'JPEG'
+# V4L2_PIX_FMT_RGB24   : 4  'RGB3'
+# V4L2_PIX_FMT_UYVY    : 5  'UYVY'
+# V4L2_PIX_FMT_YUYV    : 6  'YUYV'
+# V4L2_PIX_FMT_YUV422P : 7  '422P'
+# V4L2_PIX_FMT_YUV420  : 8  'YU12'
+v4l2_palette 3
+
 # The video input to be used (default: 8)
 # Should normally be set to 1 for video/TV cards, and 8 for USB cameras
 input 8

Now, if we rerun the daemon for the second thread, we get the following output:

[2] cap.driver: "gspca_zc3xx"
[2] cap.card: "USB Camera (046d:08a2)"
[2] cap.bus_info: "usb-musb-hdrc.1.auto-1.2"
[2] cap.capabilities=0x85000001
[2] - VIDEO_CAPTURE
[2] - READWRITE
[2] - STREAMING
[2] Test palette JPEG (320x240)
[2] Using palette JPEG (320x240) bytesperlines 320 sizeimage 29390 colorspace 00000007

Perfect! The webcams are now correctly configured.

The web interface

Now it's time to verify the video output by directly seeing a video stream. To do it, motion sets up several web servers to be used to monitor the main thread (thread numbered 0) and the per camera threads (threads numbered from 1 to N).

If we take a look at the webcam_port settings in the motion.conf, thread1.conf and thread2.conf files, we see that each thread opens a different monitoring port, as follows:

root@beaglebone:~# grep webcam_port /etc/motion/{motion,thread1,thread2}.conf
/etc/motion/motion.conf:webcam_port 8081
/etc/motion/thread1.conf:webcam_port 8081
/etc/motion/thread2.conf:webcam_port 8082

The only settings that must be modified are control_localhost and webcam_localhost, which must be set to off in order to allow a remote control connection for the first thread and a remote webcam connection for the threads of each webcam. The patch is as follows:

--- /etc/motion/motion.conf.orig   2014-04-23 21:12:18.511719124 +0000
+++ /etc/motion/motion.conf   2014-04-23 20:48:18.068359577 +0000
@@ -410,7 +410,7 @@
 webcam_maxrate 1
 
 # Restrict webcam connections to localhost only (default: on)
-webcam_localhost on
+webcam_localhost off
 
 # Limits the number of images per connection (default: 0 = unlimited)
 # Number can be defined by multiplying actual webcam rate by desired number of seconds
@@ -426,7 +426,7 @@
 control_port 8080
 
 # Restrict control connections to localhost only (default: on)
-control_localhost on
+control_localhost off
 
 # Output for http server, select off to choose raw text plain (default: on)
 control_html_output on

Note that the daemon doesn't start if the 8080 port is occupied by another running process (such as Apache, for instance). Verify that this is not this case.

Now, if we rerun the daemon, we can verify that the three motion web servers are running at the 8080, 8081, and 8082 ports using the following command line in a different terminal:

root@beaglebone:~# netstat -pnl | grep motion
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      2388/motion     
tcp        0      0 0.0.0.0:8081            0.0.0.0:*               LISTEN      2388/motion     
tcp        0      0 0.0.0.0:8082            0.0.0.0:*               LISTEN      2388/motion     

Great! Now, we can use a normal browser to connect to the main thread (thread number 0), but for us to check the webcams' output, we can get the per webcam video stream at http://192.168.7.2:8081 and http://192.168.7.2:8082, as shown in the following screenshots:

The web interface
The web interface

Tip

Note that in this last test, I executed the daemon without the -s option argument in order to disable the setup mode, that is, using the following command line:

root@beaglebone:~# motion -n

This is because I noticed that in the setup mode, the webcams work with a very bad video output (I don't know if this is a bug or a feature).

On the other hand, the control thread can be controlled via a web browser at http://192.168.7.2:8080. The following screenshot shows the main page:

The web interface

If we navigate to the All | Config | list menu entries, we reach http://192.168.7.2:8080/0/config/list, where we can get a page with all the configuration settings of the main thread, as shown in the following screenshot:

The web interface

Tip

Note that we are able to change each setting just by clicking on the relevant link and entering the new value. However, we're not going to use these interfaces to set up the system in this book.

As for the main thread, we can get the configuration of each running thread by just clicking on the relative link and then navigating to the menu. As an example, for the thread 1, we can read its current configuration at http://192.168.7.2:8080/1/config/list, as shown in the following screenshot:

The web interface

Managing events

Now it's time to see how we can perform some actions when an event occurs. The motion daemon defines several events, all reported in the main configuration file. In fact, in the /etc/motion/motion.conf file, we see the following settings (again a snippet of the file):

############################################################
# External Commands, Warnings and Logging:
# You can use conversion specifiers for the on_xxxx commands
# %Y = year, %m = month, %d = date,
# %H = hour, %M = minute, %S = second,
# %v = event, %q = frame number, %t = thread (camera) number,
# %D = changed pixels, %N = noise level,
# %i and %J = width and height of motion area,
# %K and %L = X and Y coordinates of motion center
# %C = value defined by text_event
# %f = filename with full path
# %n = number indicating filetype
# Both %f and %n are only defined for on_picture_save,
# on_movie_start and on_movie_end
# Quotation marks round string are allowed.
############################################################

# Do not sound beeps when detecting motion (default: on)
# Note: motion never beeps when running in daemon mode.
quiet on

# Command to be executed when an event starts. (default: none)
# An event starts at first motion detected after a period of no motion defined by gap
; on_event_start value

# Command to be executed when an event ends after a period of no motion
# (default: none). The period of no motion is defined by option gap.
; on_event_end value

# Command to be executed when a picture (.ppm|.jpg) is saved (default: none)
# To give the filename as an argument to a command append it with %f
; on_picture_save value
 
# Command to be executed when a motion frame is detected (default: none)
; on_motion_detected value

# Command to be executed when motion in a predefined area is detected
# Check option 'area_detect'.   (default: none)
; on_area_detected value

# Command to be executed when a movie file (.mpg|.avi) is created. (default: none)
# To give the filename as an argument to a command append it with %f
; on_movie_start value

# Command to be executed when a movie file (.mpg|.avi) is closed. (default: none)
# To give the filename as an argument to a command append it with %f
; on_movie_end value

# Command to be executed when a camera can't be opened or if it is lost
# NOTE: There is situations when motion doesn't detect a lost camera!
# It depends on the driver, some drivers don't detect a lost camera at all
# Some hang the motion thread. Some even hang the PC! (default: none)
; on_camera_lost value

These are all the possible events reported by the daemon, and here we can define the command to execute when one event occurs. We just have to enter a command file with specific arguments, and the daemon will call it at the right time. The allowed arguments are shown in the comment at the top of the preceding list.

As an example, and in order to better understand how the mechanism works, let's consider the following simple Bash script named args.sh:

#!/bin/bash

NAME=$(basename $0)
ID=$RANDOM

function log ( ) { 
    echo "$(date "+%s.%N"): $NAME-$ID: $1"
} 

log "executing with $# args"

n=1
for arg ; do 
    log "$n) $arg" 
    n=$((n + 1))
done

log "done"

exit 0

Note

The code is stored in the chapter_08/bin/args.sh script in the book's example code repository.

If we execute it from the command line, it simply prints its arguments (with a timestamp prefix) as follows:

root@beaglebone:~/chapter_08# ./args.sh arg1 "arg 2" "..." 'arg-N'
1398299270.472083231: args.sh-12334: executing with 4 args
1398299270.498241897: args.sh-12334: 1) arg1
1398299270.523545772: args.sh-12334: 2) arg 2
1398299270.548859939: args.sh-12334: 3) ...
1398299270.574398731: args.sh-12334: 4) arg-N
1398299270.599793272: args.sh-12334: done

Tip

Note that the program prints a random number after its name. This is because we'll need a unique name to distinguish between thread 1 and thread 2 (see the following section).

Now, if we copy this script in the /usr/local/bin/ directory, we can call it, as follows:

root@beaglebone:~/chapter_08# /usr/local/bin/args.sh test command line
1398299445.322540043: args.sh-13425: executing with 3 args
1398299445.348607251: args.sh-13425: 1) test
1398299445.374537126: args.sh-13425: 2) command
1398299445.400261585: args.sh-13425: 3) line
1398299445.429571918: args.sh-13425: done

We can use this program with motion in order to discover which arguments are passed to an external program when an event occurs. As an example, we can consider the on_picture_save event. We can enable it with the following patch:

--- /etc/motion/motion.conf.orig   2014-04-23 21:12:18.511719124 +0000
+++ /etc/motion/motion.conf   2015-09-11 20:58:19.334749400 +0000
@@ -518,7 +518,7 @@
 
 # Command to be executed when a picture (.ppm|.jpg) is saved (default: #none)
 # To give the filename as an argument to a command append it with %f
-; on_picture_save value
+on_picture_save /usr/local/bin/args.sh %C %t %f
 
 # Command to be executed when a motion frame is detected (default: none)
 ; on_motion_detected value

In this manner, we ask motion to execute the args.sh script when a new picture is saved, passing to it the event's timestamp, the number of the thread that generated the event, and the full path name of the picture file.

Before running the daemon again, we must make sure that, in the per thread configuration file, the same event has been disabled by commenting on the relative line, as shown, for example, for the first thread, in the following patch:

--- /etc/motion/thread1.conf.orig   2014-04-23 21:12:25.712890999 +0000
+++ /etc/motion/thread1.conf   2015-09-11 20:57:49.828890021 +0000
@@ -50,7 +69,7 @@
 
 # Command to be executed when a picture (.ppm|.jpg) is saved (default: none)
 # The filename of the picture is appended as an argument for the command.
-on_picture_save /usr/local/motion-extras/camparse1.pl
+; on_picture_save /usr/local/motion-extras/camparse1.pl
 
 # Command to be executed when a movie file (.mpg|.avi) is closed. #(default: none)

Tip

If you forget to disable the event in the webcams' threads, you'll get several errors, such as the following ones:

[2] File of type 1 saved to: /usr/local/apache2/htdocs/cam2/01-20150911205458-00.jpg
 &: 1:  &: /usr/local/motion-extras/camparse2.pl: not found
[1] File of type 1 saved to: /usr/local/apache2/htdocs/cam1/01-20150911205555-01.jpg
 &: 1:  &: /usr/local/motion-extras/camparse1.pl: not found

So, remember to disable this setting for all running threads!

Now, if we execute the daemon again and do some movement in front of a camera, we get the following messages:

[1] File of type 1 saved to: /usr/local/apache2/htdocs/cam1/01-20150911210615-00.jpg
1442005575.375926790: args.sh-7523: executing with 3 args
1442005575.386901248: args.sh-7523: 1) 20150911210615
1442005575.398043498: args.sh-7523: 2) 1
1442005575.408981165: args.sh-7523: 3) /usr/local/apache2/htdocs/cam1/01-20150911210615-00.jpg
1442005575.419728082: args.sh-7523: done

Great! Everything is working correctly. Now, it's very easy to finish the job. In fact, we have to simply replace the args.sh script with a script that sends an e-mail to us with a picture attached! A snippet of a possible implementation of such program is as follows:

#
# Local functions
#

function log ( ) { 
    echo "[$cam] $1"
}

function send_alert { 
    # Build the attachments list 
    [ ! -e $ALERT_LIST ] && return 
    for f in $(head -n $ALERT_LIMIT $ALERT_LIST) ; do 
        list="-a $f $list" 
    done 

    # Send the letter 
    echo -e ${ALERT_MESG/\%time/$time} |  
        mail -s "$ALERT_SUBJ" -r "$ALERT_FROM" $list "$ALERT_TO"
}

usage() { 
    echo "usage [to add image]: $NAME <timestamp><cam #><filepath>" >&2 
    echo "usage [to send alert]: $NAME <timestamp><cam #>" >&2 
    exit 1
}

#
# Main
#
# Check command line
[ $# -lt 2 ] && usage

( # Wait for lock on LOCK_FILE (fd 99) for 10 seconds
flock -w 10 -x 99 || exit 1

if [ $# -eq 3 ] ; then 
    # Must add the picture to the list 
    time=$1 
    cam=$2 
    path=$3 

    log "got new picture $path at $time" 
    echo "$path" >> $ALERT_LIST

elif [ $# -eq 2 ] ; then 
    # Send the mail alert 
    time=$1 
    cam=$2 

    log "sending alert at $time" 
    send_alert 
    rm $ALERT_LIST

else 

    cam="?" 
    log "invalid command!"

fi

# Release the lock
) 99>$LOCK_FILE

exit 0

Note

The complete code is stored in the chapter_08/bin/send_alert.sh script in the book's example code repository.

To use it, we have to copy it in /usr/local/bin/, as we did before, for the args.sh program. Then, we must replace all the occurrences of args.sh in the /etc/motion/motion.conf configuration file with send_alert.sh. When this is done, just rerun the motion daemon, and when a motion is detected, we should get a logging message as follows:

[1] File of type 1 saved to: /usr/local/apache2/htdocs/cam1/01-20150915210814-01.jpg
[1] got new picture /usr/local/apache2/htdocs/cam1/01-20150915210814-01.jpg at 20150915210814
[1] File of type 1 saved to: /usr/local/apache2/htdocs/cam1/01-20150915210815-00.jpg
[1] got new picture /usr/local/apache2/htdocs/cam1/01-20150915210815-00.jpg at 20150915210814
[1] File of type 1 saved to: /usr/local/apache2/htdocs/cam1/01-20150915210815-01.jpg
[1] got new picture /usr/local/apache2/htdocs/cam1/01-20150915210815-01.jpg at 20150915210814

Note that it's quite common that a lot of pictures will be taken, so without some specific anti-flooding technique, we can risk to send tons of e-mails! The trick here is quite easy—using the gap and on_event_end options, we can generate an e-mail send event once motion decides that the current event is finished. In fact, we can see the following by taking a look at the configuration filed:

# Gap is the seconds of no motion detection that triggers the end of an event
# An event is defined as a series of motion images taken within a short timeframe.
# Recommended value is 60 seconds (Default). The value 0 is allowed and disables
# events causing all Motion to be written to one single mpeg file and no pre_capture.
gap 60

We can imagine storing the filenames of the images in a list, and then, when the on_event_end event occurs, we can read back the names and send one e-mail with attachments.

To enable the on_event_end event, I used to following setting:

--- /etc/motion/motion.conf.orig   2014-04-23 21:12:18.511719124 +0000
+++ /etc/motion/motion.conf   2015-09-15 20:55:31.654352880 +0000
@@ -514,11 +514,11 @@
 
 # Command to be executed when an event ends after a period of no motion
 # (default: none). The period of no motion is defined by option gap.
-; on_event_end value
+on_event_end /usr/local/bin/send_alert.sh %C %t
 
 # Command to be executed when a picture (.ppm|.jpg) is saved (default: none)
 # To give the filename as an argument to a command append it with %f
-; on_picture_save value
+on_picture_save /usr/local/bin/send_alert.sh %C %t %f

Here, the send_alert.sh script implements this solution. If we run it without arguments, it displays a short usage message as follows:

root@beaglebone:~# ./send_alert.sh
usage [to add image]: send_alert.sh <timestamp> <cam #> <filepath>
usage [to send alert]: send_alert.sh <timestamp> <cam #>

If executed with three arguments, it stores filepath in the file addressed by the ALERT_LIST variable, while when it is executed with two arguments, it rereads the file and sends an e-mail with a number of pictures (limited by the variable ALERT_LIMIT) as attachments.

To test if the program works correctly, we can try to execute it with just two arguments, and then verify that an e-mail message arrives to our account.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.12.71.237