Security cameras: automatically recording and uploading footage when a door is opened

My last post detailed how to integrate a cheap IP cam with SmartThings. I briefly mentioned a SmartApp that took a picture when the door opened. This was pretty straightforward. I wanted to take it a step further and trigger recording when my door was opened (but no one is home). Beyond the obvious, I had the following requirements:

  1. SmartThings needs to be able toggle recording. The SmartApp should notify my household when it begins recording.
  2. Tampering with the camera shouldn’t destroy already captured footage.
  3. Footage should start uploading somewhere offsite as soon as possible.
  4. Control over uploaded footage.

I already covered (1) in my last post. My integration with the IP camera enables a scheduled recording feature, and configures this feature to always record. Switching off recording clears the schedule.

Uploading footage to S3

The camera I’m using already has builtin support to upload footage to an FTP server, which leaves everything but uploading to offsite storage.

Since it’s easy and cheap, I decided to upload footage to Amazon S3. I then needed a tool that:

  1. Watched for newly created files to appear in the directory my internal FTP server is pointed at. When a new file is detected:
  2. Immediately begin a streaming upload to S3. Since the file size isn’t known ahead of time, I made use of the multipart upload API, which allows for the breaking down of uploads into smaller (5MB) chunks.
  3. When the file is done being written to, complete the upload (i.e., tell Amazon the file is done being uploaded). This makes the file available on S3.

This seemed like a good fit for inotify, which allows for the monitoring of filesystem events. It’s possible to set up notifications that are triggered when, for example, a new file within a directory is opened, closed, or modified.

I didn’t find a tool that did exactly what I wanted, so I made a ruby library that did. I called it “s3reamer“. My sincerest apologies for being an awful portmanteau-ist. I run this on my home server:

This will automatically begin uploading to S3 when recording on the device is triggered. Here’s a snippet from the log file:

Uploading starts within a few seconds of recording being switched on. Most of that delay is waiting for the camera to begin uploading.

SmartApp to trigger recording when door opens

This part was pretty straightforward. Code below. This also sends a push notification when recording is switched on so my household knows and can react accordingly.

Integrating Foscam FI9821P with SmartThings

Motivated mostly by curiosity, I was recently in the market for a cheap IP camera. After a little bit of research, I settled on a Foscam FI9821P (I got mine for ~$45 as an Amazon Warehouse Deal). The app provided by Foscam is pretty nice, but I wanted to integrate it with my home automation setup as well. In particular, I wanted to accomplish the following:

  1. Secure access. Any communication with the camera should require some secure authentication mechanism.
  2. SmartThings integration. I wanted a device in SmartThings I could play around with.
  3. REST endpoint. Although I could probably get most of what I want done with SmartThings alone, I didn’t want to be bound to it.

SmartThings has a device type for cameras, so as long as there’s some way to access the camera within SmartThings, (2) is easy. In a previous post, I outlined a setup that uses HMAC to secure communication with smart home devices. I leveraged it in this project as well.

I should mention that I stumbled across some existing attempts at this, but nothing that would’ve given (1) and (3).

I put together this route for my home automation gateway, which accomplishes (1) and (3). With it, I can capture a snapshot and control some rudimentary functionalities of the camera. I can, for example, request a snapshot of what the camera is currently seeing simply by accessing this URL (with the appropriate security headers in place):

http://HA_GATWAY_URL/camera/foscam1/snapshot.jpg

You can see that there’s baked in support for multiple cameras (since the endpoint is scoped by a camera name). While I don’t anticipate buying more cameras, I figured adding support would make this project more generally useful.

To integrate with SmartThings, I created a virtual device (code embedded below). It allows me to request an image, shift the camera to one of three preset positions, and to start/stop recording. Here’s a demo of the interface:SmartThings Interface

This project was a lot of fun, and quite a bit easier than I was anticipating. My favorite thing this has enabled is a SmartThings SmartApp that signals the camera to take a picture when my front door opens. To avoid being too creepy, this only happens when no one is home. If I can muster the motivation, I’ll probably write a separate post about that.

Cheap alternative to Phillips Hue LED Strip

I have some RGB LED strips in my bedroom to light an area other lighting in the room doesn’t reach. The strips I bought were inexpensive, but they only interact with the included infrared remote. I wanted to be able to control these lights with SmartThings. There are a couple of ways you can do this:

Easy and spendy

Phillips has a bunch of products that integrate nicely with SmartThings. The obvious contender here is this guy. However, for this to work, you’d also need a Phillips Hue Bridge. In total, this is going to run you somewhere between $150 and $250, depending on how many feet of LED strip you want.

Partially because this seemed unreasonably expensive, but especially considering I’d already glued LED strips to my walls, this solution wasn’t appealing.

Cheap and complicated

Browsing around, I found a cheap ($30) LED controller advertising “WiFi” control (link):

It was exactly what I was hoping for. It has a tiny TCP server that allows network control. The official mobile app is actually quite good, but it doesn’t integrate with the rest of my SmartThings stuff. I toyed around a little bit and managed to reverse engineer the protocol. I put it in a rubygem, available here.

This allowed me to programmatically control the LEDs, but obviously still no integration with SmartThings. Fortunately, that wasn’t very hard either.

Design

The overall design looks something like this:

7VfLU/M2EP9rcmzGD/LgSEJoD/QbpmGm7VGxha1BtjyS8uKvZ2WtbCkGmg6kH4fmkEg/rVf7+O1uPEqX1eFXSZryd5FTPkqi/DBKb0dJcj25gm8DHC0wmVxboJAst1DcA2v2QhGMEN2ynKpAUAvBNWtCMBN1TTMdYE+Ch1c0pHDqe2CdET5E/2S5Li06T6Y9/htlRemuiafozIZkz4UU2xrvGyXpU/uxxxVxutCrQ2S3bn/EPaprSB0Y9CJEFQCSqj5S6CwLna/JLriSs/o5DNlGyJxKTyhdQSKlEKDIrKrDknKTTJeodJpF8SzJKZ0m82iS/2JV350r3oVX0hqN/bTK1OpU+uiSSHPIKW6F1KUoRE34qkcXbaKoUQlhX5S64rCMYQlmyeNfiLebv81mPIGt0kTqGynFHqCME6VY5uA7BlZaFdYcY8MJpT7wGWWU2MoMHxvIYBnBbQV9T8+kSyJUIxUVBQdasnCi2S40iCAXik6ue/RBMDAVSIoPpI6kWMG4dRqsSfhQnzsIFTG3O7HGCChfAhaenT3U5vzM/GNYdoRv0b/71e3qx+pxlExJ1UBC6o0yP7DnELdFznawLMxyKSDDgnOoATyE673zAbM8puyo1Awaxz3ZUP4gFNNMmJrdCK1NrS64OVh0bWEpuLCl5hpDr+OGs8I8q4UxVIFNz137gaQg4mmIonl0Zyj6BLx7S7MqSd7y1AjlRJUd2eGkMd5Uh8K06zETajZm0DzVGKwo9WbLN53rxkDqWHAuj4f8Qw1OBdIoadmaRPu+0c6w/ZVej71Gsbf4GhDp37AGdXqs+WO1BspEayrB6UHi9yXTdN2Qtjr3ELiwbVwiWvE8rLorbHReuGLX2v14TU+q80viNR/Eqy5YffgOcUq/U5yQv16chtOpzt8ZIkP4zMlED0ybo1YO1v3JpYYR1s+Hw6jlzDBtXl7cIPHT4rDPzqyQFKfJts4NRtZAjXsO1Tit/zD5vmKuuas8Kq0rIMljyerCTtGAVZzDH2Lz38Y1+IyLLShf/ISSnJyUpPPFL0kXWT/3cTK7QE3G6NAlivI/LzxsxB8Wng33/5X3Jl9g27/gWPH+tTVdvQI=

I’ll elaborate on each of these components in the following sections.

REST server

The TCP API works nicely, but I wanted to wrap it in something that’d be easier to interface with. I wrote a really small REST gateway using sinatra. This serves two functions:

  1. Easy access. Obviously, integrating directly with a TCP server kind of sucks in comparison to making a REST call.
  2. Security. I added a before block in the sinatra to verify HMAC codes computed using a shared secret. This prevents unauthorized parties from using this server. Wouldn’t want randos turning my lights off and on!

This little server listens for requests on port 8000.

nginx

I use nginx as the externally facing endpoint because I have a bunch internal webservers, and nginx makes it easier to manage all of them. It also adds the ability to address the webserver using a subdomain instead of a custom port. The config looks like this:

Notice the server is listening on port 81. My router opens port 80, and forwards it to port 81 on my home server. I do this because internal services I don’t want to expose to the outside world run on port 80, but I’d prefer to use port 80 from the outside world. The request chain looks something like:

Integrating with SmartThings

SmartThings has what they call “Virtual Devices“, which is a way to define a custom device in terms of its capabilities. A Virtual Device can, for example, declare that it’s a switch (giving it an on/off toggle), a switch level (giving it a dimmer slider), or a “color control” (giving it a hue/saturation control). One can also insert code that’s called whenever one of the controls changes value. Perfect!

I created the following Virtual Device based on the Phillips Hue device template that interacts with the REST server mentioned previously.

All one needs to do at this point is create a new device within SmartThings that makes use of this Virtual Device.

Conclusion

This ended up working out way better than I expected. From what I can tell, it behaves exactly like a first-class citizen within SmartThings. I’m super happy with how easy (and fun!) it was.

Updates

  1. [Oct-21, 2015] — I noticed there was a bug in the SmartThings Virtual Device signature generation method. It wasn’t properly padding signatures beginning with 0. I fixed this by using the built in byte[].encodeHex().