The camera tutorials from https://iotbreaks.com
IntroductionIn this tutorial, I am going to show you how to build a simple application that detects motion and sends notifications to the your smart phone using a Raspberry Pi and camera module. If there is something or someone moving in the camera setup's field, you will get notified to your phone or web browsers.
The notification comes with text, still image, and video that you can view it right on iOS or Android. The application is pretty simple. It utilizes the free software and services such as picamera, ffmpeg, and pushbullet.
I will walk you through the architecture, flowchart, and explain the main Python functions. At the end of this video, you can build your own application or customize the already built one as you wish.
Let's start!
Hardware- Optional: Heat sinks
- Optional: Simple case or Fancy Case
Or you can buy all-in-one set here.
Specification
This section explains the specification of application including app structure, and general flowchart. You will have a clear vision about what application does.
Application StructureThere are 3 actors that play together to build up the application:
- (1) Raspberry Pi & camera module as the data source that continuously scan for motion and recording video at the same time.
- (2) Pushbullet as the message-broker to send messages (text, still image, and videos) back and forth between Raspberry Pi and Mobile/Web
- (3) Mobile/web acts as “notifyee” who receives the still image and video of motion. The communication is two ways though. It means you can send a command from mobile or web to Raspberry Pi for particular action such as “@snap” (for instantly take a photo) or “@check” (to get current system information of Pi).
When the script launches, it takes 2 seconds to warm up the camera to make sure everything works properly. Then it jumps right into motion scanning. If moving happens, the Pi will capture a still image and send notifications to the phone immediately. At the same time, Pi keeps recording the moment for a few more seconds. After that amount of time, if movement is still there, Pi re-captures a new image and sends a new notification. Until there is no more motion, the recorded videos will be pushed to mobile to confirm the motion has ended. The system goes into motion scanning state. The program loops again and again as in this flowchart.
If you can’t wait to see it works for you, this section is for you. You will understand the source code later. For now, everything you need is to make the application up running.
Step 1: Setup PushbulletFirst, you need to register a Pushbullet account get the key for notification. Go to https://www.pushbullet.com, you can either register with Google email or Facebook. In my case, I use Gmail. After a successful signup, log in and go to Settings –> Account to create an API access token. We need this token for Raspberry Pi to push notifications. Just note them down some where.
Second, on mobile, the Pushbullet application is ready for both iOS and Android. So, install it. Make sure you log in with the pushbullet account that you just registered.
I recommend you download and install the ready-to-work image in the Resources section to save you a ton of time for necessary software and libraries setup. Otherwise, you can setup from the brand-new Jessie. That’s fine.
This application builds on top of standard Raspbian Jessie released on 2017-04-10 that downloads from the official website of Raspberry Pi. You also need ffmpeg for video conversion, from h264 to mp4, to view directly on your phone or web browser, and pushbullet python library for notification. One note for ffmpeg that it is not ready for install via “apt-get” command on Jessie, you have to compile it from the source code. The compilation time takes about 3 hours. The source code of application is mostly written in Python.
Now let's download the ready-to-work image; this file size is huge, it’s about 2.7GB. So now would be the time for coffee.
Step 3: Flash Image to PiAlright, you have downloaded the image successfully, now unzip and flash it to your SD card. I used the Sandisk micro SD card 8GB. I’m also using a MAC. In case, you don’t know how to flash image to an SD card, check this tip. If you’re on windows, you can flash with WIN32DISKIMAGER. The flash takes about 20 minutes, so coffee again (make sure you don’t drink too much).
Flash Pi Image To SD Card:
$> sudo dd bs=1m if=/[your_dowload_path]/iotbreaks_PiCameraNotifier_V1.0.img of=[The SD Card]
Step 4: Enter the Pushbullet Access TokenNow it's show time, so let's take a look how it works. Insert the SD card and power the Pi up. The application source code is placed right on the Desktop. Your only job now is to enter the Pushbullet key as follows:
main.py:
$> cd ~/Desktop/PiCameraNotifier/
$> vi main.py
Save the main.py and reboot the Pi. Enjoy the result!
Take a look at Pushbullet application on your phone, you should see a message that tells that the application is up and running. The first message should be “PiCameraNotifier app starts!”. Right swipe that message to bring you to the chat screen of Pushbullet. Later on, all images, videos, and texts from Raspberry Pi will be sent to this chat screen. Now let's try moving something in front of the camera to see the magic happen. Use QuickView on iOS to view the motion video. Here is my example.
Under The Hood
If you want to learn deeply how source code works, this section is for you. In this section, I will explain every detail about how the code works along with its flowchart. You will be able to customize the code to add new commands, change the video or image size, store files, or whatever you need.
There are 2 python files you need to care of, they are main.py and push.py. You may guest the function of each file by its name, right? main.py is all about logic of application and push.py takes care sending notification and receive the command.
main.pyAt app launch, I create two important objects – camera and notificationHandler. Those objects are used in all functions below.
Initialize two major objects at first:
camera = picamera.PiCamera()
notificationHandler = NotificationHandler(PUSHBULLET_KEY,didReceiveCommand)
def main():
global isMotionDetected
global notificationHandler
logging.info("### Initialize Camera")
cameraInitialize()
pushData = {'type': 'TEXT_MESSAGE', 'text': 'PiCameraNotifier app starts !'}
notificationHandler.pushToMobile(pushData)
We initialize camera for motion detection and recording ahead into circularIO. The reason we need to record ahead is because we want to have a video of the moment before motion detected. We have no way to predict when something will happen, so we have to record in advance.
Camera Initialize:
def cameraInitialize():
logging.info("cameraInitialize: for (1) motion detection, and (2) circularIO recording")
global camera
# for motion detection
motionAnalysisPort=2
camera.start_recording(
'/dev/null',
splitter_port=motionAnalysisPort,
resize=(640,480),
format='h264',
motion_output=DetectMotion(camera, size=(640,480))
)
# for circularIO recording
HDVideoRecordPort=1
global stream
camera.start_recording(
stream,
format="h264",
resize=(640,480),
splitter_port=HDVideoRecordPort)
When motion is detected, the function didDetectMotion() will be called. Pi will capture a still image and send a notification to mobile via captureImage() function. Then it keeps recording 2 more seconds to complete a video. That video will be pushed when the scheduled timer expires. Take a look at writeVideo() function.
Detect Motion:
class DetectMotion(picamera.array.PiMotionAnalysis):
def analyse(self,a):
global isMotionDetected
a = np.sqrt(np.square(a['x'].astype(np.float)) + np.square(a['y'].astype(np.float))).clip(0, 255).astype(np.uint8)
if(a > 60).sum() > 10:
logging.info("motion just detected")
isMotionDetected = True
didDetectMotion()
else:
isMotionDetected = False
def didDetectMotion():
global isRecordingMotion
if isRecordingMotion:
print("is Recording Motion ...")
else:
isRecordingMotion = True
print("start Recording Motion ...")
global notificationHandler
global camera
pushData = {'type': 'TEXT_MESSAGE', 'text': 'Hey! someone sneak into your room. Check it out!'}
notificationHandler.pushToMobile(pushData)
fileName=time.strftime("%Y%m%d_%I:%M:%S%p") # '20170424_12:53:15AM'
logging.info("push image...")
captureImage(fileName)
camera.wait_recording(7)
writeVideo(fileName)
isRecordingMotion = False
In case you send a command to Pi, “@snap” for example, the function didReceiveCommand will be called and processed accordingly. The same operation goes for “@check” command.
At command received:
def didReceiveCommand(command):
global notificationHandler
if command == "@check":
logging.info("get system info")
process = subprocess.Popen([ WORKING_DIR + 'systemInfo.sh'], stdout=subprocess.PIPE)
out, err = process.communicate()
pushData = {'type': 'TEXT_MESSAGE', 'text': out}
notificationHandler.pushToMobile(pushData)
if command == "@snap" :
fileName=time.strftime("%Y%m%d_%I:%M:%S%p") # '20170424_12:53:15AM'
captureImage(fileName)
else:
logging.info("Command not supported: " + command)
logging.info("send notification to response")
push.pyNow take a look at push.py which functions by transmitting and receiving the notification.
For transmission, the sending out of messages, are text, image, and videos. To minimize the crazy things that happen when sending, I use serial queue to send one after one. You can leverage the CPU by changing the maximum thread number to 2 or more
init push manager:
def __init__(self, pushBulletAPIKey,didReceiveCommand):
# Setup pushBullet manager
self.pushBulletAPIKey = pushBulletAPIKey
self.didReceiveCommand = didReceiveCommand
self.pushBulletManager = Pushbullet(self.pushBulletAPIKey)
thread = Thread(target = self.__createListener)
thread.start()
# Setup Notification Queue
self.__setupNotificationQueue()
For receiving, I use the “@” character to mark it as a command. Here I have defined two commands “snap” and “check” as you seen. You can define your own commands by copying those lines of code.
To feel the code better, you should checkout the repository and play around with it. Try to customize things like the camera resolution, video duration, text messages, or add a new command.
LogI write log to file /home/pi/Desktop/PiCameraNotifier/run.log just in case an error happens or you want to check the running status. You can change the file path by modifying the variable LOG_FILE_PATH in main.py. Here is an example of log info:
05/24/2017 02:37:06 PM =========== app launched ======== 05/24/2017 02:37:07 PM ### Setup Notification Listener 05/24/2017 02:37:07 PM Starting new HTTPS connection (1): api.pushbullet.com 05/24/2017 02:37:11 PM Start main 05/24/2017 02:37:13 PM ### Initialize Camera 05/24/2017 02:37:13 PM cameraInitialize: for (1) motion detection, and (2) circularIO recording 05/24/2017 03:21:27 PM motion just detected 05/24/2017 03:21:27 PM push image…
Auto-launch the App at Pi Boot/RebootI bet you're wondering why the application is up running automatically after rebooting the Pi as we do in above step, aren’t you? I use the systemctl to config the PiCameraNotifier as a service that runs in the background. Here is the configuration file /lib/systemd/system/PiCameraNotifier.service
At command received:
[Unit]
Description=My Sample Service
After=multi-user.target
[Service]
Type=simple
ExecStart=/home/pi/Desktop/PiCameraNotifier/main.py
[Install]
WantedBy=multi-user.target
Resources
Summary
We have a real application that detects motion, notifies your smart phone and runs on a Raspberry Pi 3. This application should work normally with a Raspberry Pi Zero or Pi 2. You may wonder if is it real time. No, it’s not real time, but fast enough to be aware of what's happening in the camera setup space. This application does not require coding skill, but you can modify the source code as you need to add more features or customize the function. We have a very clear process for real product development. We know architect, flowchart, source code... and how those things dance together.
In case you get stuck somewhere, comment your question. I will read and answer.
If you like the video, please subscribe the channel, share, and thumps up. That will inspire me to produce more helpful videos. Have a good time!
Comments