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.
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]
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.
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 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.
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]
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:
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] |
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 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.
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.
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:
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:
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:
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:
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
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
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)
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
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.
3.12.71.237