Part 2: I Spy with my Little Pi...

Something I’ve Captured In Slack!

Rob Bell and Mike Lewis

Issue 11, May 2018

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

Log in

We’re picking up from last issue, to finish off our idea with a wall plate mount, and video capture.


In last month’s Part 1, we created a Slack app as a powerful method to send photo captures to anywhere in the world. By integrating NGROK we could also request photos at any time, which is great for surveillance-type applications too (even if it’s just checking your dog hasn’t torn apart your lounge room).


Our original implementation of this project worked very well for all intents and purposes, and certainly achieved the initial goals of the project. But we wanted MORE.

We highly recommend the Raspberry Pi Zero W for this project, since it’s so much more compact. Our 3D printer files are designed for the Pi Zero, as the entire project can then be fitted to a standard-sized wall plate for clean and discrete mounting. Of course, you can use a standard Raspberry Pi 3, but you’ll have to find another method for mounting as it’s a little too large.


Last month we used Slack webhooks to post an image URL that we hosted on our Pi’s web server. This month we will add video to our application using raspivid.

The limitation of Slack’s webhooks is that we cannot upload files such as a video. Our method of posting to Slack also required the photos to be publicly accessible via a weblink which, depending on the solution, may not be appropriate.

Fortunately, Slack has a Web API that we can use for file uploads instead of using their webhooks. This gives us the added benefit of the images and videos being saved to Slack, which means they’ll remain even if our Pi goes offline. It also increases our security as we are no longer hosting our images for the world to see.


The Parts required for this build are the same as in part 1:

Parts Required:JaycarAltronics
1 x Raspberry Pi Zero W -Z6303
or Raspberry Pi 3 Model BXC9000Z6302C
1 x Raspberry Pi: NoIR Camera V2XC9020Z6306A
1 x PIR Motion DetectorXC4444Z6382

Note: 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 circuit itself is unchanged from Part 1. You simply need to connect the camera to the Raspberry Pi Zero W, and then connect your PIR as shown in the diagram.


Copy the updated code files found in the digital resources for this article.

Remove your existing application and replace with the provided code package.

Run npm install from the project’s root directory to download the dependencies.

Edit index.js and re-enter your ngrokToken (line 12) that we set up in Part 1.

Next we will create a Slack Bot User and setup authentication to their web API.

Slack’s web API works very similar to their Webhooks, which both use a HTTP POST request. The difference is that we must authenticate each time we call Slack’s API. We do this by sending our OAuth Access Token in the HTTP Authorization request header.

You can either set this up to post to Slack as yourself, or utilise a Bot user. We went with the Bot option so that our Circuit Modd friend can deliver the messages to the channel.

To create a Bot User, click “Bot Users” from the Features menu.

Enter your Bots details and click “Add Bot User”.

Follow the prompts to reinstall your app with these new settings.

Now click on “OAuth & Permissions” and copy the Bot User OAuth Access Token.

Open index.js and paste this code into the slackBotAccessToken variable on Line 13.

We must invite our Bot to a Slack channel before they can post messages. Open the channel that you installed the application on and click “Invite others to this channel”

We will also need to obtain the channel’s ID code in order to tell Slack’s API which channel to post our messages to.

Open your channel from a web browser and copy the channel ID from the pages URL

Paste into the slackChannelID variable on Line 14 of index.js.

Now let’s start our server. From the project’s root directory run:

npm start

You should receive a message to your channel containing the the generated ngrok tunnel ID.

We will be using raspivid to capture the video which comes preinstalled with the distribution of Linux we're using, Raspbian GNU/Linux 8 (Jessie).

raspivid is the command line tool for capturing video with the camera module.

raspivid will capture video as a raw H264 video stream which, unfortunately, Slack and other media players will often fail to play successfully. To avoid this, you can “wrap” it in a suitable container format like MP4, which you can obtain from the raspivid command, by using MP4Box.

To install MP4Box, type:

sudo apt-get install -y gpac

Now we have everything in place for video recording. Let's test it out.

Start your web server.

When motion is detected our application calls the captureVideo() function, which runs the command:

raspivid -o captures/1523578820215.h264 -t 10000

We've set the -t (time) argument to record the video for 10 seconds (10,000 milliseconds).

Once the raspivid command returns as complete, it will trigger another callback function which runs the following MP4Box command that creates a MP4 file from our raw H264 video file:

MP4Box -add captures/1523578820215.h264 captures/1523578820215.mp4

Then once the MP4Box command returns as successful it will trigger our final callback, which first cleans up by removing the unused H264 file:

sudo rm captures/1523578820215.h264

Then posts our video to Slack.

function postFileToSlack(file) {{
    headers: { 
        ‘content-type’  : ‘multipart/form-data; 
      ‘Authorization’ : ‘Bearer ‘ + 
    url: ‘’,
    formData: {
      channels : slackChannelID,
      file      : fs.createReadStream( 
__dirname + ‘/’ + dir + file ),
      title    : ‘Cheeeeese! :cheese_wedge:’

We can now update our Slack command to support video as well as photo requests.

Start the server and copy the ngrok tunnel address that should be posted to your Slack channel from our node application.

From the Slack app dashboard, click “Slash Commands” and Edit the /photo command we created in Part 1. We will rename it to /capture so that it makes sense when we pass a argument along with it such as /capture video.

Command: /capture
<p>Request URL: </p>

We’ve updated our node js applications code to listen for requests on /capture and determine which argument was sent in the body.text:‘/capture’, (req, res) => {
  if ( req.body.text.toLowerCase() == ‘video’ ) {
  } else {
  res.send(‘Sure, one moment please ‘ + 

Now from Slack we can use /capture video or /capture photo.

IMPORTANT NOTE! We are using a standard GPO-compliant mount, however electrical work should never be undertaken by anyone not licenced to do so. Take care when cutting or screwing into stud walls, as live wires may exist, and contact could cause injury or death.


It would be nice for our application to start automatically when our Pi boots, and we can do this quite easily!

Node.js does not have a feature to do this, so it’s up to the OS to run.

We will use Forever ( to automatically restart our application if it crashes.

sudo npm install forever -g
  forever start /home/pi/slackcam-v2/index.js

We recommend reading Forever documentation for other commands such as stop and restart.

Now we can have the system run this Forever script on start up, using Crontab:

// replace pi with your username
sudo crontab -u pi -e
// select a text editor, 2 for nano then add the following 2 lines:
@reboot /usr/local/bin/forever start /home/pi/slackcam-v2/index.js

Save and close the file (Control + X, then Y to confirm and save).

Now your system should run in the background with no terminal windows, and also start automatically if the Pi is restarted.


Possibly as important as the code theory for this project, is the complex 3D print. Well, complex probably isn’t the right word; it’s fairly basic - but without 3D printing, it would be quite a challenge!

There are three parts to the mount: the wall plate, the camera retainer, and the PIR retainer.

The print wall plate creates locating pins for the camera and PIR, while the retainer plates hold them firm against the wall plate. Integrated into the retainers for the camera and PIR are mounts for the Raspberry Pi Zero W. It is possible to use tiny screws, but very small screws can be tough (and expensive) to find, and the fine tolerances aren’t always well matched to 3D printing. This method uses standard M3 screws. It also keeps all fixing hardware on the back of the wall plate, which results in a cleaner finish. The overall result is a very tidy and compact installation.

Lastly, an optional addition, depending on how you want to install it, is a GPO spacer block. This would allow you to surface-mount the entire unit to suit your application. If you’re mounting into a cavity wall, you will probably not need the spacer block. Of course, these fit all standard GPO hardware, so you can use off-the-shelf bracketry and hardware to install.


A little care needs to be taken to mount everything accurately into the printed case. So we’ve taken it step-by-step.

CAMERA: Install the camera as shown in the pictures, taking care not to place stress on the camera cable. Locate the camera on the four locating pins, then screw down the retainer plate. The M3 screws we’re using aren’t self-tapping, but we don’t find the need to tap threads like this in 3D prints - just use a little muscle where required. It is possible to insert the camera cable post-installation, but it’s easier to leave it connected.

PIR: Install the PIR, locate it on the pins, and insert the retaining plate as shown in the images. The orientation of the PIR doesn’t really matter, but to keep the plug out of the way, we recommend inserting it as shown.

THE RASPBERRY PI ZERO W: Locate the Raspberry Pi Zero W as shown, and take care with the camera cable. Screw it down using four screws until firm. Don’t over-tighten things; just firm.

POWER: It’s important to note that if you’re using a mounting block, you may not be able to get a USB cable into the socket on the Raspberry Pi Zero W. The simplest solution is to provide power directly to the GPIO pins.


This really does provide a powerful system. Leveraging the Slack platform, you can have push notifications, and access things from anywhere in the world.

If your WiFi router is prone to restarting, you’ll definitely benefit from a static URL with ngrok. However if you’re only using the PIR-based triggering, and don’t need to request images of videos you can omit the ngrok functionality entirely, as the system will push updates to Slack without ngrok.