Security cam blog posts on Tumblr

Room with a View

Author(s):

When the Perlmeister is on the road, he likes to know what's going on at home. Armed with just two scripts, he draws on the Tumblr API to store snapshots cyclically from his home security camera.

When I'm traveling, knowing that my home is threatened neither by fire nor by an invading band of thieves contributes greatly to my sense of well-being. To avoid phoning my neighbors to satisfy my security cravings, I installed a panning camera to keep a watchful eye on the skyline of San Francisco through my living room window (Figure 1). The Foscam FI 8910W [1], which costs about US$  60 and includes a WiFi connection, supports remote control via the Internet and lets me stream the video to my mobile phone  – no matter where I happen to be.

Figure 1: The panning Foscam camera in the Perlmeister's living room watches over downtown San Francisco.

Quirky Camera

Before you indulge in impulse purchases, be warned: The cheap Foscam camera has some annoying quirks. For example, when it's dark, the camera always turns its infrared LED ring on after rebooting, which happens every now and then for some unknown reason. This feature sounds useful at first, but if the camera is set up directly in front of a reflecting window, the whole thing turns into a fiasco, with the camera dazzling itself until someone notices and switches off the infrared ring by hand.

Thus far, customers have waited in vain for a firmware update that rescues them from this feature. "You get what you pay for," as people say laconically here in the US. Also, the camera's web interface looks like a relic from the last century: Users are given a jerky video stream and can use the control buttons at the top left to pan the camera head about 300 degrees laterally and tilt 120 degrees upward (Figure 2).

Figure 2: The frugally featured and visually obsolete Foscam camera web interface.

The fact that the built-in Foscam server wants you to supply your password in plain text via HTTP instead of via HTTPS is another faux pas that rational users will tend to counteract with a VPN if they need to transmit images over the Internet.

If your camera is set up at home and you want to access it from the outside, your router's firewall will need to use port forwarding to forward the incoming requests. Because the camera works with a dynamic DNS service, the web interface is always accessible at the same URL, such as http://<XXX>.myfoscam.org:5148, independent of the dynamically assigned WAN IP.

On My Mark  – Blog!

Because I happen to own the camera, I have to try to make the best of it. One of my first conclusions is that it makes more sense to grab snapshots regularly with the camera and dump them onto the Internet, instead of dialing up the camera periodically to make sure everything is okay. A script can then line up the still images on a web page  – and one look is all it takes for a daily routine check. So, that is exactly my plan for this month's Perl column.

To help me in this noble cause, I noticed that the Tumblr microblogging platform, which my employer, Yahoo, acquired about six months ago, has a programmable API [2]. A quick check on CPAN showed that avid open source programmers had already published a matching Perl module named WWW::Tumblr. The rest was clear sailing: A cron job executes the script presented in Listing 2 several times a day and grabs a snapshot with the camera.

The script then routes the image via the API to my Tumblr blog, which shows the messages in reverse chronological order and offers all kinds of social platform bells and whistles such as Like buttons or reblog functions (Figure 3). Because most Tumblr users follow several blogs, you can add the sequence of home security images to your follow list and consume them along with other postings (Figure 4).

Figure 3: Each time the tumblr-post script is called, a still image from the camera is added to the Tumblr blog.
Figure 4: Once the blog has been added to your follow list, its postings appear in your stream with other publications.

OAuth Grants Access to Tumblr Blog

For the tumblr-post Perl script to be allowed write access to a user's blog automatically, you need to register it as a Tumblr application. Additionally, the user needs to grant the application appropriate rights. These steps are described in Tumblr's API documentation [2].

Figure 5 shows the registration process for the Perlsnapshot test application, and because it is a script  – and not an app for the iPhone or an Android device  – I have left the App Store URL and Google Play URL fields blank.

Figure 5: After registering the application …

The Default callback URL, that is, the Web address that Tumblr invokes with the generated access tokens after authorization by the user is http://localhost:8082 (Figure 6). As an application icon, I just uploaded a 128x128 pixel self-portrait.

Figure 6: … and specifying the callback URL…

After clicking on Register below the completed form, Tumblr shows you a consumer key and a secret key (Figure 7). These two hex strings identify a registered Tumblr application, which in turn is allowed to ask users for access rights.

Figure 7: … the Tumblr API page happily generates an OAuth token.

Module Mojo

As in previous Perl columns [3] featuring OAuth-controlled Perl applications such as Google Drive, Listing 1 [4] also uses the Mojolicious module from CPAN to ask permission to publish blog entries. When launched by typing ./tumblr-oauth, it outputs the message:

Listing 1

tumblr-oauth

 

[Sat Oct 12 09:56:27 2013] [info]
Listening at "http://localhost:8082".
Server available at http://localhost:8082.

and then launches a web server on port 8082 of localhost. If a browser now requests the URL http://localhost:8082, the script just sends a link with the text Login on Tumblr. When you click the link, you are taken to the Tumblr login page, where you need to identify yourself with your email address and password, if you were not already logged in.

Tumblr then displays the dialog shown in Figure 8 to the user, asking permission for the Perlsnapshot application to read and write to the blog. The blog I set up previously for test purposes under the name of "Schtonk's Rants" at schtonk.tumblr.com will be used for the camera images later on. If the user now presses Allow, Tumblr refers the browser back to the previously set callback URL (http://localhost:8082) and hands over two access tokens to the local web server: oauth_token and oauth_verifier.

Figure 8: The user authorizes the script for posting new articles on Tumblr.

Armed with these tokens, the recipient can mess around with the users' blogs  – within the constraints of the permissions  – as if logged in as the users themselves. However, application users do not need to share a password but only a token, which they can revoke at any time.

A Local Web Server

To do this, Listing 1 draws on the CPAN WWW::Tumblr::Authentication::OAuth module, which includes the necessary URLs for retrieving tokens. The variables in lines 15 and 16 contain the $consumer_key and $secret_key values obtained in Figure 7 on registering the application.

Before the Mojolicious::Lite module starts the server, it expects some options on the command line. Against all expectations, the daemon option starts the web server in the foreground and --listen is assigned the local URL to listen to in line 13. To avoid the need to pass in command-line parameters to tumblr-oauth, line 28 unceremoniously stuffs the options into the @ARGV array and then foists them onto the Mojolicious module.

Browser requests for port 8082 without a path are fielded by the code starting in line 34, which sets the stash variable login_url and thus converts the template in the DATA area of the script, starting in line 90, into an HTML page with a login link, which the browser then displays. If Tumblr redirects back to the Mojolicious server after obtaining permission from the user, this happens in the /callback path, and the code from line 45 is executed.

Line 62 uses DumpFile() from the CPAN YAML module to store all four tokens received, as well as two new access tokens created with token() and token_secret(), respectively, in YAML-readable format in the .tumblr.yml file in the home directory. Application scripts later access the file, read the tokens, and thus gain access to the user's blog.

Shots Through the Window

Listing 2 shows the actual application that grabs photos from the surveillance camera. In line 16, you need to insert the address of your own camera, plus the username and password for the camera's web interface in lines 20 and 21. The WWW::Mechanize type object's credentials() method stores this information and automatically adds it to web requests when the camera's web server asks for a password. All you really need to retrieve data from a web server is the Perl LWP::UserAgent module, but the WWW::Mechanize superclass provides a more convenient credentials() method that requires fewer parameters.

Listing 2

tumblr-post

 

The Foscam camera delivers a snapshot of its field of view as /snapshot.cgi; the blurt() function from the CPAN Sysadm::Install module writes the image data to a local file named snapshot.jpg in lines 27 and 28.

Conclusions and Future

Now, the Tumblr features come into play. Line 31 reads the YAML file with the tokens, and line 33 creates a new object of the WWW::Tumblr type. Drawing on the Tumblr API, line 43 then retrieves the details of the previously defined test blog (schtonk.tumblr.com) and the post() method sends the image file content to the Tumblr server, specifying the type as photo. Then, $post indicates success with a true value. If you then launch the script by typing ./tumblr-post, the response is the ID of the newly created blog entry:

I have published post id: 63791478637

Unfortunately, the API provides no way to attach an image caption. This method currently seems to work only via a browser interface that allows HTML pages with embedded photos. Theoretically, however, the script could upload text and reference the images on a different server. For the surveillance photos, however, it is more convenient for me to store the images on Tumblr.

A viable alternative would be a caption in the image itself, as presented in last month's Perl column using the CPAN Imager module. In this way you could add brief texts to the image – for example, the current outdoor temperature.

The Author

Mike Schilli works as a software engineer with Yahoo! in Sunnyvale, California. He can be contacted at mailto:mschilli@perlmeister.com. Mike's homepage can be found at http://perlmeister.com.