The Doorbell Notification Project: Part 2

In Part 1 I showed you how I wired up my existing doorbell button to trigger an event on my home automation system. But for this whole project to be of any use, we have to do something interesting with that event.

In my case, I wanted to be able to hear the doorbell when I was downstairs in my home theater, which is ridiculously well-soundproofed, with two solid-wood doors closing it off from the rest of the house.

Simple Notifications

The first and most obvious way to get a notification would be on my phone. I had discovered Prowl a while back as a nifty API-based way to have software send me notifications, so I decided to use that. Once you buy Prowl you get an API Key you can use to send yourself messages like this:

My home automation unit, VeraLite, can easily be configured to hit a given URL. It uses the scripting language Lua, so it's easy to have random code execute whenever an event is triggered:

The second wget call is what I use to play the doorbell sound in the kitchen using my doorbell microservice discussed in Part 1.

Notice, however, that the first wget call is not hitting the Prowl API directly. Instead, it's using a service called PushingBox. PushingBox is another great free service that you can use to manage all manner of notifications. It can, in turn, hit your Prowl API key for you, as well as any random URLs. So when the doorbell is rung, you can configure a Scenario to do lots of things:

Kodi Integration

As you can see, simply having my wife and I get notifications on our phones via Prowl is only the beginning. I wanted to take it a step further and also get a notification on the big screen in case my phone wasn't handy.

My home theater software setup is driven mostly by some amazing open-source software called Kodi, formerly titled XBMC. It is designed for home theater enthusiasts, and can catalog and play your library of TV Shows, Movies, and Music with aplomb. It also can serve as a TV/PVR front-end, so if you use any one of a number of PC-based DVR solutions, you can watch recorded or live TV on Kodi as well.

Most of the time I'm in the theater I'm using Kodi to watch TV or movies. So getting a notification is pretty easy: Kodi has a very robust JSON-based API and it's trivially easy to get a popup notification:

http://<kodi-ip>:<kodi-port>/jsonrpc?request=<url-encoded-request>

in my case, the URL-encoded-request I needed looks like this:

{ jsonrpc: 2.0, method: GUI.ShowNotification, params: { title: "Doorbell", message: "Someone's at the door" }, id: 1 }

and that's it! When invoked, you get a popup on the screen in Kodi:

One problem with invoking the Kodi API like this, though, is that the call is a POST operation, and therefore it's not so easy to have the VeraLite, or PushingBox for that matter, invoke it. Instead, I needed to turn this into a GET. So I simply wrote a quick JSP and hosted it on my own website, which takes 3 request parameters:

  • location: a keyword to identify which Kodi instance in the house to display the message on (I have five).
  • title: title of the message (ie, Doorbell)
  • message: the content of the message (ie, 'Someone at door')

The JSP would then make the call to the relevant Kodi "locations" within the house on PushingBox's behalf.

For what it's worth, here's the simple (but admittedly ugly) JSP:

<%@ page import="java.net.*, java.util.*"%>  
<html>  
  <head>
    <title>XBMC Notify</title>
  </head>
    <body>
    <%
      Map urlMap = new HashMap();
      urlMap.put("kitchen", "http://192.168.1.185:8080");
      urlMap.put("theater", "http://192.168.1.188:8080");
      urlMap.put("familyroom", "http://192.168.1.4:8080");
      urlMap.put("recroom", "http://192.168.1.197:8080");
      urlMap.put("bedroom", "http://192.168.1.184:8080");

      String title = request.getParameter("title");
      String message = request.getParameter("message");
      String baseUrl = (String) urlMap.get(request.getParameter("location"));
      baseUrl = baseUrl == null ? (String)urlMap.get("theater") : baseUrl;
      String url = baseUrl + "/jsonrpc?request=" +
        URLEncoder.encode("{ \"jsonrpc\": \"2.0\", \"method\":   \"GUI.ShowNotification\", \"params\": { \"title\": \"" + title + "\", \"message\": \"" + message + "\" }, \"id\": 1 }");

      if (message != null) {
        URL urlObj = new URL(url);
        HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();
        conn.setRequestMethod("GET");
        int statusCode = conn.getResponseCode();
        if (statusCode != HttpURLConnection.HTTP_OK) {
          out.println("Method failed: ");
        }
        out.println(conn.getResponseMessage());
      }
    %>
    <p/>
    Message "<strong><%=request.getParameter("title")%>:</strong> <%=request.getParameter("message")%>" sent to <%=request.getParameter("location")%> (<%=baseUrl%>)!

  </body>
</html>

I simply configured the URL to this page to be a "Service" in PushingBox. It's also reusable for other events other than the doorbell, like the garage or other doors opening in the house, or any other event that I might want the VeraLite to tell me about onscreen.

Xbox Notifications

So with that working, to cover all the bases, I set about the final notification type. Although I spend most of my time in the theater playing TV or movies, my son and I also play video games on the Xbox down there. If we were doing that when the doorbell rang, the Kodi notifications would go unseen.

What if I could also deliver myself a message via Xbox Live?

I set about determining if Microsoft offered an API to do that - and of course... they don't.

Instead, I found a third-party service called Xbox One API which presumably screen-scrapes the xbox.com web pages to simulate an API. Registering my gamertag with them gave me 120 API hits per hour for free - hopefully far more than I'd ever need from people ringing my doorbell!

The next step was to get PushingBox to call this API for me. Once again, it was a POST-based request, but in this case, I wanted it to be slightly fancier than the cruddy JSP I used for Kodi - now I figured I could finally make use of Spring Boot the way I wanted to originally to play the doorbell sound in the kitchen.

I have a Debian server which runs my website, this blog, and handful of other useful applications. It's a fairly recent addition to the Johnson Server Farm, so unlike my Mac Mini, it is easily able to run such an application. I only had to write a simple RESTful service and expose it through my website so that PushingBox could see it.

The code for the web service can be found here. If you want to use it to do something similar, you can edit the application.properties file to add your own Xbox API Key as well as Xbox Live XUID (which you can look up here) and you're in business.

Apache to Rule Them All

In my case, since I front RossJohnson.org with Apache, I had to also expose this service through the AJP Connector, which allows you to proxy from Apache to the embedded Tomcat that Spring Boot uses.

To get Apache to proxy this application for my specific URL, I had to add the following to my default site configuration file:

<IfModule jk_module>  
        JkMount /*.jsp ajp13_worker
        JkMount /<path-to-xbox-notifications> embedded_worker1
</IfModule>  

The first JkMount line sends all JSP requests to the tomcat server running as ajp13_worker, and the xbox notifications to the service defined by embedded_worker1. Both of these workers are defined in the workers.properties file as outlined in the jk.conf file in my Apache installation.

For me, my entries in workers.properties look like this:

worker.ajp13_worker.port=8009  
worker.ajp13_worker.host=localhost  
worker.ajp13_worker.type=ajp13

worker.embedded_worker1.port=9901  
worker.embedded_worker1.host=localhost  
worker.embedded_worker1.type=ajp13  

8009 is the port my main Tomcat instance runs on, which hosts the Kodi notification JSP page, and 9901 is the port that the Xbox notifier runs on.

With all that set up, now whenever the doorbell gets pressed, we get alerts on 3 Kodi instances, 2 phones, and my one Xbox Live account. We shouldn't be missing any pizza deliveries now!

© 2016Ross Johnson