Well, some hundred or more hours spent, I have a grasp on how to set up a motion activated camera with my Raspberry Pi.
At first, I spent some time with PiKrellCam, which has some really great features, but it works only (or best) with the Pi camera. You can read my opinion on PiKrellCam elsewhere – but ultimately, I decided to use Motion (aka The Motion Package or The Motion Project). Also, after getting Amazon’s Echo “Alexa” installed and working with the Playstation Eye webcam, I decided that using cheap webcams works just as well than the more expensive Pi camera for sheer motion detection.
Initially, I installed Motion and fiddled with it, using one of the many installation web tutorials, but it took me two weeks to actually find the project page. This was due to the name, which is regrettably named something so common that it’s impossible to find. It’s like creating a backup program and calling it “Backup”; good luck finding it. Please, please rename it to MotionNV, MotionXYZ or something that I can use in a search string.
To put this into context, I’m pretty new to Linux and the Raspberry Pi. I started on this quest about four months ago, so I’ve learned a lot in a short period. And initially, I was setting up a security cam, but half way through my project, I decided to create a Granny Cam instead to put at my Granny’s house.
Also, since I was fooling with so many uses for the Pi, I installed a shedload of applications on it, including MotionPie. I decided not to use MotionPie, because it seemed like unnecessary overhead, and I could never get it to look like it does on its project page. To make it easier to replicate, I decided to install Motion from a clean Raspbian image – this burned up one entire beautiful spring Saturday, because the Motion installer fails to properly permit the /var/lib/motion directory – therefore, it fails when run. I thought it was a problem with the camera, because when I started Motion, the camera would turn off.
The fix to the /var/lib/motion directory problem is fairly easy, and I found it in the forum. But first, I changed the target_dir in motion.conf, then I changed the target_dir:
mkdir /home/pi/MotionFiles sudo chgrp motion /home/pi/MotionFiles sudo chmod g+rwx /home/pi/MotionFiles sudo chmod -R g+w /home/pi/MotionFiles/
Holy Moses. This sent me down the wrong rabbit hole. In the future, I shall ALWAYS check permissions. And how I found it was by running Motion in non-daemon mode by:
This showed me the permissions error that got me on the right track. I didn’t know I could run it this way, because the only way I knew how to run it was:
sudo service motion start
It was around this time that I found the Motion documentation. And while thorough, it fails to provide examples. And since I’m new at python, BASH, Linux, etc. it made it SO much harder to figure out simple commands without examples.
Everything in Motion.Conf
Ultimately, I set the image capture option to “center”, because I don’t want to capture video nor the entire event in photos. Here are the lines I changed in motion.conf:
daemon on logfile /tmp/motion.log width 640 height 480 framerate 15 output_pictures center quality 100 ffmpeg_output_movies off target_dir /home/pi/MotionFiles snapshot_filename %Y%m%d_%H%M%S-snapshot picture_filename %Y%m%d_%H%M%S-motion-%q stream_port 8765 stream_quality 100 stream_maxrate 5 stream_auth_method 1 stream_authentication myusername:mypassword webcontrol_port 8766 webcontrol_localhost on webcontrol_authentication myusername:mypassword on_event_start python /home/pi/scripts/on_event_start mo_%H%M%S sql_log_picture on sql_query insert into security(camera, filename, frame, file_type, time_stamp, event_time_stamp, Other) values('%t', '%f', '%q', '%n', '%Y-%m-%d %T', '%C', '%D|%i|%J|%K|%L') database_type mysql database_dbname motion database_host localhost database_user myusername database_password mypassword database_port 3306
Side note: to view all config settings:
grep ^[[:alpha:]] /etc/motion/motion.conf
Many of these are self-explanatory, but some are definitely not. I removed the %v (event#) from the file name, because when I view them in a GUI, they don’t sort by date. Here are the variables that you can use for file name or even file output:
# %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
Adding functionality outside of Motion is part of the fun, so of course I added a Python script:
on_event_start python /home/pi/scripts/on_event_start.py motion
Initially, I tried using a BASH script, but it wouldn’t work – this is where an example would really help. Anyway, I probably should start using Python instead. Here’s my on_event_start.py:
#!/usr/bin/python import urllib import sys import os
def rndmp3 (): file = '/home/pi/Music/alarm.mp3' os.system ('omxplayer ' + file)
arg1 = sys.argv url = "http://www.mywebsite.com/recordIP.php?motion=” + arg1 content = urllib.urlopen(url).read() print url rndmp3 ()
This script kicks off my PHP script that logs the IP address of the Pi (because it’s connected to via DHCP, so there’s no guarantee that it will be the same). I could have made this PHP script do more, but I’d like the Pi to do as much as possible by itself. It also plays an alarm MP3, which is pretty annoying.
What is missing from the capture data is the event duration. I had to work around this deficiency by adding two new fields and add it to the MySQL database: start and end date/time.
I also installed MySQL to capture every event and its details:
mysql> create database motion; mysql> CREATE USER 'myusername'@'localhost' IDENTIFIED BY 'mypassword'; mysql> GRANT ALL PRIVILEGES ON motion.* TO 'myusername'@'%' WITH GRANT OPTION; mysql> use motion; mysql> CREATE TABLE security ( EID int NOT NULL AUTO_INCREMENT, camera int, filename char(80) not null, frame int, file_type int, time_stamp TIMESTAMP, event_time_stamp TIMESTAMP, Other varchar(100), start DATETIME, end DATETIME, PRIMARY KEY (EID) );
Then create a python script to update the database on event end:
UPDATE security SET start = security.time_stamp, end = '2017-05-04 10:05:18' WHERE filename ='/home/pi/MotionFiles/20170504_091534-motion-03.jpg';
It copies the original event start timestamp to the start field, and add an end timestamp to the end field. I think this will be helpful when identifying events. Some events are just a few seconds, while others are much longer. Plotting this trend will allow me to monitor general activity.
And for trending purposes, this is critical. Here is the logic tree:
Saves center image.
Logs in db.
IP address captured externally.
# of pixels changed
# of seconds long is the event
# of events per day
# of pixels changed per hour, per day
# of seconds is an event per hour, per day
# of minutes without event – if x hours passes without event, then email.
If the trend is low, send email:
Subject: Granny Low Activity
Body: Average pixels changed per day is ###. Today’s average: ###
But I’m really jumping ahead to the end of the story. I spent hours and hours on this, trying to get the damn thing to do what I wanted.
I created a BASH script that checks the event log for Motion:
grep "motion_detected: Motion detected – starting event" /tmp/motion.log
And I created an SSH monitor to keep an eye on login attempts. Did I mention that I opened up the Pi to SSH? Well, I did. But before I did that, I changed my SSH port to something other than 22, changed the Pi user password, and installed Fail2Ban.
Allow Motion to Write to USB Drive
It seems like every step of the way involves days-long research. For example, I was able to get Motion to write to a file in /home/pi/MotionFiles, but I read that it’s not good for the SD card to write so often, so I added a USB drive to the Pi.
Adding the USB drive is a pain in the ass too, because initially it is auto-mounted at a location where I don’t want it. So to mount it every time I boot the Pi to a mount point that I like, I had to edit /etc/fstab, but first, I had to find the UUID of the drive. This means that I have to unmount it first.
Shows where I DON’T want it mounted (it’s sda1):
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 1 2G 0 disk +-sda1 8:1 1 2G 0 part /media/pi/8C24-0A33 [this is the usb drive default mount point] mmcblk0 179:0 0 7.4G 0 disk +-mmcblk0p2 179:2 0 7.4G 0 part / +-mmcblk0p1 179:1 0 41M 0 part /boot
Get the UUID of the drive. You’ll need this for the fstab line.
Look for “sda1” – it’s along string, like “1231536e-d084-4569-8bea-d425d71d8de6”
Now unmount it:
sudo umount /media/pi/8C24-0A33
To make matters easier, I also reformatted the vfat USB to ext4. You have to unmount the drive before doing this. I don’t recall the exact steps here, but it’s something like:
sudo mkfs.ext4 /dev/sda1
In the future, I probably will keep the drive set to vfat so I can swap it out to a Windows machine.
Create the mount point where you want it:
sudo mkdir /media/usbdrive
sudo mkdir /media/usbdrive/MediaFiles
The directory: /media/usbdrive will be the mount point.
Now edit fstab:
At the end of the text file, add:
UUID=1231536e-d084-4569-8bea-d425d71d8de6 /media/usbdrive ext4 nofail,defaults 0 0
Now that it’s in fstab, remount it using:
If it gives you an error, don’t try rebooting! It means that your fstab line is wrong somehow. Fix it and mount -a again until you get no errors. If you continue to get errors, don’t reboot! If you do, it will hang (probably), and you’ll have to connect a display/keyboard to then edit /etc/fstab. If you do reboot and get the hang, don’t use sudo – use just nano /etc/fstab.
Yay – now you have a USB drive mounted in a location that you want and it mounts on boot.
But Motion doesn’t have write access, so you might think that changing group permissions would work:
sudo chgrp motion /media/usbdrive/MotionFiles
Alas it did not. So what I did instead, is I added the “motion” user to the “pi” group:
sudo adduser motion pi
I then edited the motion.conf file and changed the target_dir
sudo nano /etc/motion/motion.conf
Now if all goes well, you can sudo service motion start and it will write to the new location.
Most Common Commands
sudo service motion start
sudo service motion stop
sudo service motion restart
sudo service motion status
Although you can run just “motion status”, “sudo service motion status” is the one that checks the daemon.
Motion Starts then Stops
If it’s running at first then immediately shuts down when detecting motion, then it’s likely that the target directory can’t be written to. Make sure your permissions are correct, and make sure the disk isn’t FULL:
The Motion web page on your Pi is:
Online Help is here:
Copy Files from Pi
Use the pscp command from a Windows terminal. 1234 represents the port. I think pscp is installed when you install Putty.
pscp -P 1234 -pw yourPiPassword email@example.com:/home/pi/MotionFiles/*.jpg D:\Trash\MotionFiles
List the drives:
sudo fdisk -l
cd /etc/motion sudo cp motion.conf motion.orig sudo nano /etc/motion/motion.conf stream_localhost on - >stream_localhost off on = only stream to localhost and don't allow it anywhere else. You want this OFF sudo nano /etc/default/motion start_motion_daemon=no -> start_motion_daemon=yes sudo service motion start Navigate to the default URL: yourpiIPaddress:8081
List USB Devices
Get the uuid of the usb drive
Look for sda1
See what user is running the Motion daemon:
ps aux | grep -v grep | grep motion
motion 29741 12.6 1.7 71424 15260 ? Sl 15:54 0:00 /usr/bin/motion
The first item should be “motion” and not “root” or anything else.
Different Ways to Run Motion:
motion start = will start motion as user pi
sudo motion start = starts motion as user root
sudo service motion start = starts motion as user motion