Projects

Part 1: I Spy With My Little Pi...

Rob Bell and Mike Lewis

Issue 10, April 2018

This article includes additional downloadable resources.
Please log in to access.

Log in

Using just a few dollars of hardware, you can create an intelligent camera monitoring system. There’s no firewall holes to drill, and integrates seamlessly with Slack.

BUILD TIME: 1 Hour
DIFFICULTY RATING: Intermediate

THE BROAD OVERVIEW

This is a project that’s useful in a few different ways. It’s a simple device that integrates a motion detector (called a “passive infrared detector”, or “PIR”), which triggers your Raspberry Pi to take a snapshot from the camera. In order to send that photo somewhere useful, we’re creating a Slackbot, which integrates into the Slack app. Within certain limitations Slack is free to use, so you can leverage their technology, smartphone app, and multi-user access, to provide a simple review of the uploaded content. This will also provide us with the ability to request a photo from the camera at any time, by communicating with our Pi. Awesome!

This means that whenever someone (or something) walks past your motion detector, an image is captured and transmitted. Using the Slack app you can monitor for updates on your phone or computer, no matter where you are at the time!

HOW IT WORKS

There are five parts to this project:

  1. The Raspberry Pi Zero W (can be a standard Pi 3, we just wanted to fit it into a wallplate, which we’ll build out in Part 2).
  2. The Raspberry Pi camera (the NoIR version is a good option for night vision as it has infrared LEDs too).
  3. The PIR which provides motion-based triggering.
  4. The Slackbot which receives photos from our Pi.
  5. ngrok which allows bi-directional communication through a firewall (which can be skipped if you don’t want the ability to request a photo).

Our device requires two-way communication, so there are certain steps to take to make this happen.

SENDING MESSAGES TO SLACK

To post messages to Slack, we send a JSON object via a HTTP POST request, to Slack’s webhook API, These messages can contain attachments; in our case we will attach an image URL.

RECEIVING COMMANDS FROM SLACK

To receive Slack commands we need a way for the internet to contact our device via a HTTP POST.

To achieve this we could use a broker service or run a web server from our device. We went with the web server option, since we can also use it to host our photos.

We will also need a public facing address (opens access to our local app from the internet), but for development purposes we may not want to go down the path of setting up port-forwarding, obtaining a static IP address from our ISP, setting up DNS records to point to our router’s IP address, or dealing with the security issues that this can bring. So we will explore a free third party service that accepts traffic on a public address, and relays that traffic to our local device.

THE BUILD

Pi zero
Parts Required: Jaycar Altronics
1 x Raspberry Pi Zero W - Z6303
or Raspberry Pi 3 Model B XC9000 Z6302C
1 x Raspberry Pi: NoIR Camera V2 XC9020 Z6306A
1 x PIR Motion Detector XC4444 Z6382

You can use a standard Raspberry Pi camera if lighting in dark environments is not an issue. The Jaycar part listed above is not a NoIR version. If using a Raspberry Pi Zero, you’ll also need a suitable cable, due to the differences in camera connection between the camera and Pi. The standard included camera cable will not fit a Raspberry Pi Zero W.

The hardware connections are VERY simple. Most of the setup is at a software level.

STEPS:

  • Set up Pi and web server
  • Create a Slack app
  • Setup ngrok tunnel
  • Run the web server
  • Create a Slack command
  • Add motion detection

SET UP PI AND WEB SERVER

We’re using Raspbian GNU/Linux 8 (Jessie), which was included on the NOOBS SD card, This comes packaged with raspistill, which we will use to take the photos. This guide assumes you’ve attached and enabled your Pi camera, and connected the Pi to your WiFi, which are fairly easy steps.

Install Node.js:

The Pi Zero uses the ARMv6 CPU. Unfortunately apt-get install nodejs installs a version of node built for ARMv7, so we’ll have to install it manually.

sudo apt-get update

Download and extract:

wget https://nodejs.org/dist/v9.5.0/node-v9.5.0-linux-armv6l.tar.gz
tar -xzf node-v9.5.0-linux-armv6l.tar.gz

Install:

sudo cp -R node-v9.5.0-linux-armv6l/* /usr/local/

Add to Path:

To use the node and npm commands you need to add the location we installed node (/user/local/bin) to your path.

nano ~/.profile

Add PATH=$PATH:/usr/local/bin then press ctrl + X and type Y to save.

Now you should be able to run:

node -v

To set up an express web server:

mkdir ~/slackcam && cd ~/slackcam

Next, download the code package from our website and copy files over. The directory should then contain these files:

| slackcam
| -- index.js
| -- package.json
| -- public/ (used to store and serve our photos)

Now run:

npm install

This will create a node_modules directory and download the required dependencies, as outlined in the package.json file.

CREATE A SLACK APP

You will need to create a Slack account. To do so, head over to https://slack.com/ and sign up for an account and workspace.

To create your Slack app, go to https://api.slack.com/apps and select “Create an App”.

Choose the App name and select your workspace.

Next, we'll create a Slack Webhook. This will be the end-point that we can post our messages to.

Slack auth screenshot

From the “Features” menu, select “Incoming Webhooks” and enable it. Click on “Add New Webhook to Workspace” and select the channel you’d like the bot to post to.

Slack provides an example cURL request that we can test. Copy the sample code and paste it into a terminal with cURL installed.

Slack webhook

If all went to plan you should see a post from your app in your selected channel.

Slack message

Copy the Webhook URL then open the index.js file, and paste the code into the slackWebhook variable on line 13.

const slackWebhook = '';

SETUP THE NGROK TUNNEL

ngrok is an awesome, lightweight tool that creates a secure tunnel on your local device, along with a public URL you can use for browsing your local site.

NGROK image

ngrok listens on the same port that your local web server is running on, and proxies external requests to your device.

You will need to generate an ngrok authtoken.

You can use this service as a guest, however you will be limited to around five hours up-time after each connection. To remove this restriction, create a free account at https://dashboard.ngrok.com/user/signup

Members can also monitor their tunnel status via ngrok’s dashboard. Once signed in, copy your authtoken.

NGROK authtoken

Open the index.js file and paste the code into the ngrokToken variable on line 12.

const ngrokToken = ''

RUN THE WEB SERVER

From the projects root directory run:

  node index.js

You should receive a new Slack message from your app:

Slack message

You should also see the following terminal output:

terminal output

Make a note of your ngrok URL, to use in our Slack command.

Try and open your ngrok URL in a web browser. If all goes to plan you will see a page with the text “Ngrok is working!”

CREATE A SLACK COMMAND

From your app’s dashboard in Slack, click on “Slash Commands” and then “Create New Command”.

Enter the following:

Command: /photo
Request URL: Use the ngrok url followed by /photo 
Slack command

Note: The limitation with a free ngrok account is that you will need to update this “Request URL” field every time you restart your Pi web server, since a new ngrok URL will be generated each time. ngrok offers paid plans to reserve domains from around $5/month, which would circumvent this issue entirely. But if you’d prefer to keep it free you can do so with this caveat.

With that in place, we can now issue the following command in Slack:

/photo 
Slack command Slack message

HOW DOES THIS WORK?

Our server listens for POST routes to /photo and Slack requires that a response is returned within three seconds. Since taking and storing a photo could potentially take longer than this, we take note of the URL contained within the Slack commands POST data, then we return a response to confirm the command was received and we’re working on it.

res.send('Sure, one moment please');

Now we can take the photo by running the raspitstll command:

raspistill -w 640 -h 480 -o public/[number].jpg -ex sports --nopreview --timeout 1

Finally once node’s file system (fs) module confirms the new jpg file has been created, we can send another POST request to the response_url containing the photo’s URL.

request.post({
  headers: {'content-type' : 'application/json'},
  url:    response_url,
  body:   JSON.stringify({
  response_type: 'in_channel',
  text: 'Here's your photo ' + user_name,
  attachments:[{
      title: date,
      image_url: ngrokURL + '/' + filename
    }]
  })
}, function(error, response, body) {
  if ( body === 'ok') {
    console.log('successfully posted to Slack');
  } 
});

ADD MOTION DETECTION

Connect your motion sensor to pin 7, as well as power, as shown.

Pi zero Fritz

Restart your web server. You will need to update your Slack command’s Request URL with the newly generated ngrok URL.

You should see the following post once motion is detected:

Slack message

WHERE TO FROM HERE?

In Part 2, we’re going to build this into a full case for installation. What’s perhaps more exciting however, is that we’re also going to attempt to enhance functionality by taking video, and posting that snippet to Slack instead. We’ll also explore some other functionality, which will make this a viable security device, behaving like a doorphone. Of course, in its current format, it’s a great “bedroom intrusion detector”, or perhaps an “office intrusion detector” for those of us who are a little older! We’ll also look to enhance security, given your photos are accessible to anyone with the ngrok URL.

As with any automatic and potentially concealed camera, we should note that it is illegal to use devices like this where there’s an expectation of privacy, such as bathrooms and change rooms. Using it on your front door however, is perfectly acceptable!

NEXT: PART 2: Something I've Captured In Slack!